├── .gitignore ├── .gitmodules ├── 3rdparty └── CMakeLists.txt ├── CMakeLists.txt ├── README.md ├── doc ├── Android.md ├── Emscripten.md ├── Linux.md ├── Mac.md └── Windows.md └── sdlms ├── CMakeLists.txt ├── Components ├── AnimatedSprite.cpp ├── AnimatedSprite.h ├── Avatar.cpp ├── Avatar.h ├── Camera.cpp ├── Camera.h ├── Component.cpp ├── Component.h ├── DistanceSprite.cpp ├── DistanceSprite.h ├── HVMove.cpp ├── HVMove.h ├── HVTile.cpp ├── HVTile.h ├── LimitTransform.cpp ├── LimitTransform.h ├── Line.cpp ├── Line.h ├── Physic │ ├── Normal.cpp │ └── Normal.h ├── Player.cpp ├── Player.h ├── RandomInput.cpp ├── RandomInput.h ├── RelativeTransform.cpp ├── RelativeTransform.h ├── Sound.cpp ├── Sound.h ├── Sprite.cpp ├── Sprite.h ├── Transform.cpp ├── Transform.h ├── Video.cpp └── Video.h ├── Core ├── ECSSystem.h ├── File.cpp ├── File.h ├── FreeType.cpp ├── FreeType.h ├── Input.cpp ├── Input.h ├── Map.cpp ├── Map.h ├── MathHelper.h ├── Window.cpp ├── Window.h ├── World.cpp └── World.h ├── Entities ├── BackGround.cpp ├── BackGround.h ├── Border.cpp ├── Border.h ├── Character.cpp ├── Character.h ├── ChatBalloon.cpp ├── ChatBalloon.h ├── Entity.cpp ├── Entity.h ├── FootHold.cpp ├── FootHold.h ├── LadderRope.cpp ├── LadderRope.h ├── Mob.cpp ├── Mob.h ├── NameTag.cpp ├── NameTag.h ├── Npc.cpp ├── Npc.h ├── Obj.cpp ├── Obj.h ├── Portal.cpp ├── Portal.h ├── String.cpp ├── String.h ├── Tile.cpp ├── Tile.h ├── Timer.cpp └── Timer.h ├── Resource ├── Resource.h ├── Wz.cpp └── Wz.h ├── Systems ├── CameraSystem.cpp ├── CameraSystem.h ├── DeltaTimeSystem.cpp ├── DeltaTimeSystem.h ├── InputSystem.cpp ├── InputSystem.h ├── PhysicSystem.cpp ├── PhysicSystem.h ├── RenderSystem.cpp ├── RenderSystem.h ├── SoundSystem.cpp ├── SoundSystem.h ├── SpriteSystem.cpp ├── SpriteSystem.h ├── System.h ├── TransformSystem.cpp ├── TransformSystem.h ├── VideoSystem.cpp └── VideoSystem.h └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | data 3 | .vscode 4 | font 5 | ffmpeg 6 | .vs -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wzlibcpp"] 2 | path = 3rdparty/wzlibcpp 3 | url = https://github.com/PShocker/wzlibcpp.git 4 | [submodule "freetype"] 5 | path = 3rdparty/freetype 6 | url = https://github.com/freetype/freetype.git 7 | [submodule "SDL"] 8 | path = 3rdparty/SDL 9 | url = https://github.com/libsdl-org/SDL.git 10 | branch = release-2.30.x 11 | -------------------------------------------------------------------------------- /3rdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(freetype) 2 | add_subdirectory(SDL) 3 | add_subdirectory(wzlibcpp) 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19.2) 2 | project(sdlMS) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | # Add compile information for LSP 7 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 8 | 9 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 10 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") 11 | # 启用lto -flto=auto 12 | # 把 MINGW-根目录\libexec\gcc\x86_64-w64-mingw32\13.2.0 下的 liblto_plugin.dll,复制到 MINGW-根目录\lib\bfd-plugins 13 | # 去掉调试符号 14 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s") 15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") 16 | # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto=auto") 17 | 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s") 19 | # 对本机cpu生成特定优化代码,可能存在兼容性问题 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") 21 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=auto") 22 | endif() 23 | endif() 24 | 25 | add_subdirectory(3rdparty) 26 | 27 | add_subdirectory(sdlms) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **实验版本已发布,采用SDL3,ENTT,请切换到new分支查看** 2 | 3 | 试玩地址:https://pshocker.github.io/sdlMS_online/sdlMS.html 4 | 5 | 用SDL2复刻冒险岛,使用[cmake(MinGW)](https://github.com/niXman/mingw-builds-binaries/releases/tag/13.2.0-rt_v11-rev0)构建. 6 | 7 | 资源文件进QQ群760717877下载 8 | 9 | 快速拉取本项目 10 | ``` 11 | git clone --recurse-submodules https://github.com/PShocker/sdlMS.git --depth 1 12 | ``` 13 | 14 | **[Windows编译](doc/Windows.md)** 15 | 16 | **[Linux编译](doc/Linux.md)** 17 | 18 | **[Emscripten编译(WEB)](doc/Emscripten.md)** 19 | 20 | **[Android编译(Android Studio)](doc/Android.md)** 21 | 22 | **[Mac编译](doc/Mac.md)** 23 | -------------------------------------------------------------------------------- /doc/Android.md: -------------------------------------------------------------------------------- 1 | **Android编译(Android Studio Iguana | 2023.2.1 Patch 1)** 2 | 3 | 把根目录SDL文件夹的```android-project```提取出来,然后把项目放到```android-project\app\jni``` 4 | 5 | ``` 6 | └── android-project 7 | ├── app 8 | │ ├── jni 9 | │ │ ├── freetype 10 | │ │ ├── SDL 11 | │ │ ├── sdlms 12 | │ │ ├── wzlibcpp 13 | │ │ └── CMakeLists.txt(替换) 14 | ``` 15 | 16 | 修改```android-project\app\build.gradle```去掉mk编译,使用cmake编译,并且使用```c++_shared``` 17 | ``` 18 | externalNativeBuild { 19 | // ndkBuild { 20 | // arguments "APP_PLATFORM=android-21" 21 | // abiFilters 'arm64-v8a' 22 | // } 23 | cmake { 24 | arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_shared" 25 | // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' 26 | abiFilters 'arm64-v8a' 27 | } 28 | } 29 | ``` 30 | ``` 31 | externalNativeBuild { 32 | // ndkBuild { 33 | // path 'jni/Android.mk' 34 | // } 35 | cmake { 36 | path 'jni/CMakeLists.txt' 37 | } 38 | } 39 | ``` 40 | 修改```android-project\app\build.gradle```指定ndk版本 41 | ``` 42 | android { 43 | ndkVersion "26.3.11579264" // e.g., ndkVersion "21.3.6528147" 44 | } 45 | ``` 46 | 47 | AndroidManifest.xml配置读取sdcard权限 48 | ``` 49 | 50 | 51 | ``` 52 | 53 | 修改```android-project\app\src\main\java\org\libsdl\app\SDLActivity.java```申请读取文件权限(安卓11以上) 54 | ```java 55 | private void requestManageExternalStoragePermission() { 56 | Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); 57 | intent.setData(Uri.parse("package:" + getPackageName())); 58 | startActivityForResult(intent, 0); 59 | } 60 | // Setup 61 | @Override 62 | protected void onCreate(Bundle savedInstanceState) { 63 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 64 | if (!Environment.isExternalStorageManager()) { 65 | requestManageExternalStoragePermission(); 66 | } 67 | } 68 | ...... 69 | } 70 | ``` 71 | 72 | **资源文件放进/sdcard/Data/** 73 | -------------------------------------------------------------------------------- /doc/Emscripten.md: -------------------------------------------------------------------------------- 1 | **emscripten编译** 2 | 3 | 配置emscripten环境 4 | https://emscripten.org/docs/getting_started/downloads.html 5 | 6 | ``` 7 | cd build 8 | emcmake cmake .. 9 | emmake make -j8 10 | python -m http.server 8500 11 | ``` 12 | emscripten编译zlib可能会有问题,如果出现打不开的情况需要重新编译一次 13 | -------------------------------------------------------------------------------- /doc/Linux.md: -------------------------------------------------------------------------------- 1 | **DeepinV23/Debian/Ubuntu编译** 2 | ```bash 3 | sudo apt-get install libsdl2-dev libfreetype-dev 4 | # 安装ffmpeg相关库 5 | sudo apt-get install libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev 6 | cd build 7 | cmake -DLINUX=1 .. 8 | make -j8 9 | ``` -------------------------------------------------------------------------------- /doc/Mac.md: -------------------------------------------------------------------------------- 1 | **Mac编译** 2 | 3 | **确保你的clang支持c++20** 4 | 5 | 一、安装FFMPEG 6 | 访问[FFMPEG官方网站](https://ffmpeg.org/download.html),下载xz源码包,或者进群下载. 7 | 或者使用brew安装 8 | ``` 9 | brew install ffmpeg 10 | ``` 11 | 1.解压 12 | ```bash 13 | tar xvf ffmpeg-7.0.tar.xz 14 | cd ffmpeg-7.0 15 | ``` 16 | 2.配置FFMPEG编译选项 17 | ``` 18 | ./configure --enable-static --disable-shared --disable-ffmpeg --disable-ffplay --disable-debug --disable-doc --disable-asm --prefix=/usr/local 19 | ``` 20 | 3.编译和安装 21 | ``` 22 | make 23 | make install 24 | ``` 25 | 26 | 二、编译sdlMS 27 | ``` 28 | cd build 29 | cmake .. 30 | make -j8 31 | ``` 32 | 编译后的文件在 33 | ``` 34 | build/bin 35 | ``` 36 | -------------------------------------------------------------------------------- /doc/Windows.md: -------------------------------------------------------------------------------- 1 | **MinGW编译** 2 | ``` 3 | cd build 4 | cmake .. 5 | make -j8 6 | ``` 7 | MinGW的make默认是```mingw32-make.exe```,需要改名为```make.exe``` 8 | 9 | **VS编译** 10 | 11 | VS2022打开项目,编译 -------------------------------------------------------------------------------- /sdlms/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(FFMPEG_INCLUDE "E:\\mygame\\Maple\\sdlMS2\\FFMPEG\\include") 3 | set(FFMPEG_LIB "E:\\mygame\\Maple\\sdlMS2\\FFMPEG\\lib") 4 | 5 | include_directories( 6 | ${CMAKE_CURRENT_SOURCE_DIR} 7 | ) 8 | 9 | include_directories( 10 | ${FFMPEG_INCLUDE} 11 | ) 12 | 13 | set(wzlibcpp ${PROJECT_SOURCE_DIR}/3rdparty/wzlibcpp) 14 | include_directories( 15 | ${wzlibcpp} 16 | ${wzlibcpp}/include 17 | ${wzlibcpp}/mio/include 18 | ) 19 | 20 | link_directories( 21 | ${FFMPEG_LIB} 22 | ) 23 | 24 | file(GLOB SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/**/*.cpp) 25 | 26 | if(WIN32) 27 | add_executable(sdlMS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${SOURCE_FILES}) 28 | # 将 SDL2 库链接到可执行文件中 29 | target_link_libraries(sdlMS PRIVATE SDL2-static SDL2main) 30 | # 链接 wzlib 库 31 | target_link_libraries(sdlMS PRIVATE wzlib) 32 | # 链接 FFMPEG库 33 | target_link_libraries(sdlMS PRIVATE avformat avdevice avcodec avutil swscale avfilter swresample) 34 | # freetype 35 | target_link_libraries(sdlMS PRIVATE freetype) 36 | # 链接 Windows平台库(FFMPEG) 37 | target_link_libraries(sdlMS PRIVATE bcrypt ws2_32 Secur32 Strmiids) 38 | # 链接 FFMPEG依赖库,wzlib里面已经包含了zlib库 39 | if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 40 | # 使用微软编译器 41 | add_definitions(-DNOMINMAX) 42 | else() 43 | # 使用 Mingw 编译器 44 | target_link_libraries(sdlMS PRIVATE bz2-1 iconv-2 lzma-5) 45 | endif() 46 | 47 | set_target_properties(sdlMS PROPERTIES 48 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} 49 | ) 50 | endif() 51 | 52 | if(LINUX) 53 | add_executable(sdlMS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${SOURCE_FILES}) 54 | # 将 SDL2 库链接到可执行文件中 55 | target_link_libraries(sdlMS PRIVATE SDL2-static SDL2main) 56 | # 链接 wzlib 库 57 | target_link_libraries(sdlMS PRIVATE wzlib) 58 | # 链接 FFMPEG库 59 | target_link_libraries(sdlMS PRIVATE avformat avdevice avcodec avutil swscale avfilter swresample) 60 | # freetype 61 | target_link_libraries(sdlMS PRIVATE freetype) 62 | set_target_properties(sdlMS PROPERTIES 63 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} 64 | ) 65 | endif() 66 | 67 | # 设置 Emscripten 编译选项 68 | if(EMSCRIPTEN) 69 | add_executable(sdlMS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${SOURCE_FILES}) 70 | # 将 SDL2 库链接到可执行文件中 71 | target_link_libraries(sdlMS PRIVATE SDL2-static SDL2main) 72 | # 链接 wzlib 库 73 | target_link_libraries(sdlMS PRIVATE wzlib) 74 | # 链接 FFMPEG库 75 | target_link_libraries(sdlMS PRIVATE avformat avdevice avcodec avutil swscale avfilter swresample) 76 | # freetype 77 | target_link_libraries(sdlMS PRIVATE freetype) 78 | 79 | set(CMAKE_EXECUTABLE_SUFFIX ".html") 80 | set_target_properties(sdlMS PROPERTIES LINK_FLAGS 81 | "--preload-file ${CMAKE_SOURCE_DIR}/build/Data/@Data/" 82 | # 可以添加其他Emscripten链接器选项 83 | ) 84 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -sALLOW_MEMORY_GROWTH -g -sUSE_ZLIB") 85 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -sALLOW_MEMORY_GROWTH -g -sUSE_ZLIB") 86 | set_target_properties(sdlMS PROPERTIES 87 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} 88 | ) 89 | endif() 90 | 91 | if(ANDROID) 92 | add_library(main SHARED) 93 | target_sources(main PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${SOURCE_FILES}) 94 | find_library(SDL2 SDL2) 95 | target_link_libraries(main SDL2 android) 96 | # 链接 wzlib 库 97 | target_link_libraries(main wzlib) 98 | # 链接 FFMPEG 库 99 | target_link_libraries(main avformat avdevice avcodec avutil swscale avfilter swresample -Wl,-Bsymbolic) 100 | # freetype 101 | target_link_libraries(main freetype) 102 | endif() 103 | 104 | if (APPLE) 105 | # Find packages 106 | find_library(COREMEDIA_FRAMEWORK CoreMedia) 107 | find_library(VIDEOTOOLBOX_FRAMEWORK VideoToolbox) 108 | find_library(SECURITY_FRAMEWORK Security) 109 | 110 | add_executable(sdlMS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ${SOURCE_FILES}) 111 | 112 | # 将 SDL2 库链接到可执行文件中 113 | target_link_libraries(sdlMS PRIVATE SDL2-static SDL2main) 114 | 115 | # 链接 wzlib 库 116 | target_link_libraries(sdlMS PRIVATE wzlib) 117 | # 链接 FFMPEG库 118 | target_link_libraries(sdlMS PRIVATE avformat avdevice avcodec avutil swscale avfilter swresample) 119 | # freetype 120 | target_link_libraries(sdlMS PRIVATE freetype) 121 | 122 | # Link frameworks 123 | target_link_libraries( 124 | sdlMS 125 | PRIVATE 126 | ${COREMEDIA_FRAMEWORK} 127 | ${VIDEOTOOLBOX_FRAMEWORK} 128 | ${SECURITY_FRAMEWORK} 129 | ) 130 | 131 | set_target_properties(sdlMS PROPERTIES 132 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 133 | ) 134 | endif() 135 | -------------------------------------------------------------------------------- /sdlms/Components/AnimatedSprite.cpp: -------------------------------------------------------------------------------- 1 | #include "AnimatedSprite.h" 2 | 3 | AnimatedSprite::AnimatedSprite(wz::Node *node, int alpha) 4 | { 5 | // 从第0帧顺序读 6 | for (int i = 0; i < node->children_count(); i++) 7 | { 8 | auto it = node->get_child(std::to_string(i)); 9 | if (it == nullptr) 10 | { 11 | // 如果发现没读取到,说明已经读完,则退出读取 12 | break; 13 | } 14 | wz::Property *canvas; 15 | if (it->type == wz::Type::UOL) 16 | { 17 | auto uol = dynamic_cast *>(it); 18 | canvas = dynamic_cast *>(uol->get_uol()); 19 | } 20 | else if (it->type == wz::Type::Canvas) 21 | { 22 | canvas = dynamic_cast *>(it); 23 | } 24 | else 25 | { 26 | continue; 27 | } 28 | 29 | Sprite *sprite = new Sprite(canvas, alpha); 30 | 31 | sprites.push_back(sprite); 32 | } 33 | if (node->get_child(u"zigzag") != nullptr) 34 | { 35 | // 如果存在zigzag属性,则认为属于zigzag动画 36 | z = true; 37 | } 38 | 39 | anim_size = sprites.size(); 40 | anim_index = 0; 41 | anim_time = 0; 42 | } 43 | 44 | AnimatedSprite::~AnimatedSprite() 45 | { 46 | for (auto &spr : sprites) 47 | { 48 | delete spr; 49 | } 50 | } -------------------------------------------------------------------------------- /sdlms/Components/AnimatedSprite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Sprite.h" 8 | #include "wz/Property.hpp" 9 | 10 | class AnimatedSprite : public Component 11 | { 12 | private: 13 | std::vector sprites; 14 | int anim_index; 15 | int anim_time; 16 | int anim_size; 17 | bool animate = true; // 是否播放动画,特殊情况,冰冻状态下会暂停动画 18 | bool z = false; // ziazag 19 | 20 | public: 21 | AnimatedSprite(wz::Node *node, int alpha = 255); 22 | ~AnimatedSprite(); 23 | void add_anim_time(const int val) { anim_time += val; } 24 | 25 | auto get_anim_time() { return anim_time; } 26 | auto get_anim_index() { return anim_index; } 27 | auto get_anim_size() { return anim_size; } 28 | auto get_zigzag() { return z; } 29 | auto get_animate() { return animate; } 30 | auto get_current_sprite() { return sprites[anim_index]; } 31 | auto get_anim_delay() { return sprites[anim_index]->delay; } 32 | auto get_anim_width() { return sprites[anim_index]->get_width(); } 33 | auto get_anim_height() { return sprites[anim_index]->get_height(); } 34 | auto &get_sprites() { return sprites; } 35 | 36 | void set_anim_index(const int val) { anim_index = val; } 37 | void set_anim_time(const int val) { anim_time = val; } 38 | void set_animate(const bool val) { animate = val; } 39 | }; -------------------------------------------------------------------------------- /sdlms/Components/Avatar.cpp: -------------------------------------------------------------------------------- 1 | #include "Avatar.h" 2 | #include "Resource/Wz.h" 3 | #include 4 | 5 | Avatar *Avatar::load() 6 | { 7 | [[unlikely]] 8 | if (!inited) 9 | { 10 | inited = true; 11 | init(); 12 | } 13 | return new Avatar(); 14 | } 15 | 16 | void Avatar::init() 17 | { 18 | character_node = World::get_world()->get_resource().Character->get_root(); 19 | { 20 | auto body_node = character_node->find_from_path(u"00002000.img"); 21 | auto head_node = character_node->find_from_path(u"00012000.img"); 22 | for (auto stance_node : body_node->get_children()) 23 | { 24 | auto ststr = stance_node.first; 25 | 26 | uint16_t attackdelay = 0; 27 | 28 | for (uint8_t frame = 0; auto frame_node = stance_node.second[0]->get_child(std::to_string(frame)); ++frame) 29 | { 30 | if (frame_node->get_child(u"action") != nullptr) 31 | { 32 | /* code */ 33 | } 34 | else 35 | { 36 | auto type = type_map.at(ststr); 37 | auto delay_node = frame_node->get_child(u"delay"); 38 | auto delay = 100; 39 | if (delay_node != nullptr) 40 | { 41 | delay = dynamic_cast *>(delay_node)->get(); 42 | } 43 | stance_delays[type][frame] = delay; 44 | 45 | auto face_node = frame_node->get_child(u"face"); 46 | auto face = true; 47 | if (face_node != nullptr) 48 | { 49 | face = dynamic_cast *>(face_node)->get(); 50 | } 51 | show_face[type][frame] = face; 52 | 53 | std::unordered_map> body_shift_map; 54 | 55 | for (auto part_node : frame_node->get_children()) 56 | { 57 | auto part_name = part_node.first; 58 | 59 | if (part_name != u"delay" && part_name != u"face") 60 | { 61 | auto part = part_node.second[0]; 62 | if (part->type == wz::Type::UOL) 63 | { 64 | part = dynamic_cast *>(part)->get_uol(); 65 | } 66 | 67 | auto zstr = dynamic_cast *>(part->get_child(u"z"))->get(); 68 | auto z = layer_map.at(zstr); 69 | 70 | for (auto map_node : part->get_child(u"map")->get_children()) 71 | { 72 | auto v = dynamic_cast *>(map_node.second[0])->get(); 73 | 74 | body_shift_map[z].emplace(map_node.first, SDL_FPoint{(float)v.x, (float)v.y}); 75 | } 76 | } 77 | } 78 | std::string frame_str = std::to_string(frame); 79 | auto h = head_node->find_from_path(ststr + u"/" + std::u16string{frame_str.begin(), frame_str.end()} + u"/" + u"head"); 80 | if (h != nullptr) 81 | { 82 | if (h->type == wz::Type::UOL) 83 | { 84 | h = dynamic_cast *>(h)->get_uol(); 85 | } 86 | for (auto map_node : h->get_child(u"map")->get_children()) 87 | { 88 | auto v = dynamic_cast *>(map_node.second[0])->get(); 89 | 90 | body_shift_map[Layer::HEAD].emplace(map_node.first, SDL_FPoint{(float)v.x, (float)v.y}); 91 | } 92 | } 93 | 94 | body_positions[type][frame] = body_shift_map[Layer::BODY][u"navel"]; 95 | 96 | arm_positions[type][frame] = body_shift_map.count(Layer::ARM) ? (body_shift_map[Layer::ARM][u"hand"] - body_shift_map[Layer::ARM][u"navel"] + body_shift_map[Layer::BODY][u"navel"]) 97 | : (body_shift_map[Layer::ARM_OVER_HAIR][u"hand"] - body_shift_map[Layer::ARM_OVER_HAIR][u"navel"] + body_shift_map[Layer::BODY][u"navel"]); 98 | hand_positions[type][frame] = body_shift_map[Layer::HAND_BELOW_WEAPON][u"handMove"]; 99 | head_positions[type][frame] = body_shift_map[Layer::BODY][u"neck"] - body_shift_map[Layer::HEAD][u"neck"]; 100 | face_positions[type][frame] = body_shift_map[Layer::BODY][u"neck"] - body_shift_map[Layer::HEAD][u"neck"] + body_shift_map[Layer::HEAD][u"brow"]; 101 | hair_positions[type][frame] = body_shift_map[Layer::HEAD][u"brow"] - body_shift_map[Layer::HEAD][u"neck"] + body_shift_map[Layer::BODY][u"neck"]; 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | void Avatar::add_body(const std::u16string &val) 109 | { 110 | auto body_node = character_node->find_from_path(val + u".img"); 111 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 112 | { 113 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 114 | { 115 | auto no_str = std::to_string(no); 116 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 117 | { 118 | Sprite *sprite = new Sprite(body_node->find_from_path(type + u"/body")); 119 | Transform *f = new Transform(); 120 | auto z = std::any_cast(sprite->get_z()); 121 | auto part = *zmap[z]; 122 | part[i][no] = {f, sprite}; 123 | } 124 | { 125 | if (body_node->find_from_path(type + u"/arm") != nullptr) 126 | { 127 | auto arm_pos = dynamic_cast *>(body_node->find_from_path(type + u"/arm/map/hand"))->get(); 128 | Sprite *sprite = new Sprite(body_node->find_from_path(type + u"/arm")); 129 | Transform *f = new Transform(arm_positions[i][no] - SDL_FPoint{(float)arm_pos.x, (float)arm_pos.y}); 130 | auto z = std::any_cast(sprite->get_z()); 131 | auto part = *zmap[z]; 132 | part[i][no] = {f, sprite}; 133 | } 134 | } 135 | { 136 | if (body_node->find_from_path(type + u"/hand") != nullptr) 137 | { 138 | auto hand = body_node->find_from_path(type + u"/hand"); 139 | if (body_node->find_from_path(type + u"/hand/map/navel") != nullptr) 140 | { 141 | auto hand_pos = dynamic_cast *>(hand->find_from_path(u"map/navel"))->get(); 142 | Sprite *sprite = new Sprite(hand); 143 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)hand_pos.x, (float)hand_pos.y}); 144 | auto z = std::any_cast(sprite->get_z()); 145 | auto part = *zmap[z]; 146 | part[i][no] = {f, sprite}; 147 | } 148 | } 149 | } 150 | { 151 | if (body_node->find_from_path(type + u"/lHand") != nullptr) 152 | { 153 | auto lHand = body_node->find_from_path(type + u"/lHand"); 154 | if (lHand->find_from_path(u"map/handMove") != nullptr) 155 | { 156 | auto lHand_pos = dynamic_cast *>(lHand->find_from_path(u"map/handMove"))->get(); 157 | Sprite *sprite = new Sprite(lHand); 158 | Transform *f = new Transform(hand_positions[i][no] - SDL_FPoint{(float)lHand_pos.x, (float)lHand_pos.y}); 159 | auto z = std::any_cast(sprite->get_z()); 160 | auto part = *zmap[z]; 161 | part[i][no] = {f, sprite}; 162 | } 163 | else 164 | { 165 | auto lHand_pos = dynamic_cast *>(lHand->find_from_path(u"map/navel"))->get(); 166 | Sprite *sprite = new Sprite(lHand); 167 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)lHand_pos.x, (float)lHand_pos.y}); 168 | auto z = std::any_cast(sprite->get_z()); 169 | auto part = *zmap[z]; 170 | part[i][no] = {f, sprite}; 171 | } 172 | } 173 | } 174 | { 175 | if (body_node->find_from_path(type + u"/rHand") != nullptr) 176 | { 177 | auto rHand = body_node->find_from_path(type + u"/rHand"); 178 | if (rHand->find_from_path(u"map/navel") != nullptr) 179 | { 180 | auto rHand_pos = dynamic_cast *>(rHand->find_from_path(u"map/navel"))->get(); 181 | Sprite *sprite = new Sprite(rHand); 182 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)rHand_pos.x, (float)rHand_pos.y}); 183 | auto z = std::any_cast(sprite->get_z()); 184 | auto part = *zmap[z]; 185 | part[i][no] = {f, sprite}; 186 | } 187 | } 188 | } 189 | } 190 | } 191 | } 192 | 193 | void Avatar::add_coat(const std::u16string &val) 194 | { 195 | auto coat_node = character_node->find_from_path(u"Coat/" + val + u".img"); 196 | if (coat_node != nullptr) 197 | { 198 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 199 | { 200 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 201 | { 202 | auto no_str = std::to_string(no); 203 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 204 | { 205 | if (coat_node->find_from_path(type + u"/mail") != nullptr) 206 | { 207 | auto coat_pos = dynamic_cast *>(coat_node->find_from_path(type + u"/mail/map/navel"))->get(); 208 | Sprite *sprite = new Sprite(coat_node->find_from_path(type + u"/mail")); 209 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)coat_pos.x, (float)coat_pos.y}); 210 | auto z = std::any_cast(sprite->get_z()); 211 | auto part = *zmap[z]; 212 | part[i][no] = {f, sprite}; 213 | } 214 | } 215 | { 216 | if (coat_node->find_from_path(type + u"/mailArm") != nullptr) 217 | { 218 | auto mail_arm_pos = dynamic_cast *>(coat_node->find_from_path(type + u"/mailArm/map/navel"))->get(); 219 | Sprite *sprite = new Sprite(coat_node->find_from_path(type + u"/mailArm")); 220 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)mail_arm_pos.x, (float)mail_arm_pos.y}); 221 | auto z = std::any_cast(sprite->get_z()); 222 | auto part = *zmap[z]; 223 | part[i][no] = {f, sprite}; 224 | } 225 | } 226 | } 227 | } 228 | } 229 | } 230 | 231 | void Avatar::add_cap(const std::u16string &val) 232 | { 233 | auto cap_node = character_node->find_from_path(u"Cap/" + val + u".img"); 234 | if (cap_node != nullptr) 235 | { 236 | cap_vslot.clear(); 237 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 238 | { 239 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 240 | { 241 | auto no_str = std::to_string(no); 242 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 243 | if (cap_node->find_from_path(type) != nullptr) 244 | { 245 | for (auto it : cap_node->find_from_path(type)->get_children()) 246 | { 247 | auto cap = it.second[0]; 248 | if (cap->type == wz::Type::UOL) 249 | { 250 | cap = dynamic_cast *>(cap)->get_uol(); 251 | } 252 | auto cap_pos = dynamic_cast *>(cap->find_from_path(u"map/brow"))->get(); 253 | Sprite *sprite = new Sprite(cap); 254 | Transform *f = new Transform(face_positions[i][no] - SDL_FPoint{(float)cap_pos.x, (float)cap_pos.y}); 255 | auto z = std::any_cast(sprite->get_z()); 256 | auto part = *zmap[z]; 257 | part[i][no] = {f, sprite}; 258 | } 259 | } 260 | } 261 | } 262 | auto vslot = dynamic_cast *>(cap_node->find_from_path(u"info/vslot"))->get(); 263 | for (size_t i = 0; i < vslot.size(); i += 2) 264 | { 265 | cap_vslot.emplace(vslot.substr(i, 2)); 266 | } 267 | } 268 | } 269 | 270 | void Avatar::add_pants(const std::u16string &val) 271 | { 272 | auto pants_node = character_node->find_from_path(u"Pants/" + val + u".img"); 273 | if (pants_node != nullptr) 274 | { 275 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 276 | { 277 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 278 | { 279 | auto no_str = std::to_string(no); 280 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 281 | if (pants_node->find_from_path(type + u"/pants") != nullptr) 282 | { 283 | auto pants_pos = dynamic_cast *>(pants_node->find_from_path(type + u"/pants/map/navel"))->get(); 284 | Sprite *sprite = new Sprite(pants_node->find_from_path(type + u"/pants")); 285 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)pants_pos.x, (float)pants_pos.y}); 286 | auto z = std::any_cast(sprite->get_z()); 287 | auto part = *zmap[z]; 288 | part[i][no] = {f, sprite}; 289 | } 290 | } 291 | } 292 | } 293 | } 294 | 295 | void Avatar::add_head(const std::u16string &val) 296 | { 297 | auto head_node = character_node->find_from_path(val + u".img"); 298 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 299 | { 300 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 301 | { 302 | auto no_str = std::to_string(no); 303 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 304 | if (head_node->find_from_path(type + u"/head") != nullptr) 305 | { 306 | Sprite *sprite = new Sprite(head_node->find_from_path(type + u"/head")); 307 | Transform *f = new Transform(head_positions[i][no]); 308 | auto z = std::any_cast(sprite->get_z()); 309 | auto part = *zmap[z]; 310 | part[i][no] = {f, sprite}; 311 | } 312 | } 313 | } 314 | } 315 | 316 | void Avatar::add_face(const std::u16string &val) 317 | { 318 | auto face_node = character_node->find_from_path(u"Face/" + val + u".img/default/face"); 319 | if (face_node != nullptr) 320 | { 321 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 322 | { 323 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 324 | { 325 | auto face_pos = dynamic_cast *>(face_node->find_from_path(u"map/brow"))->get(); 326 | Sprite *sprite = new Sprite(face_node); 327 | Transform *f = new Transform(face_positions[i][no] - SDL_FPoint{(float)face_pos.x, (float)face_pos.y}); 328 | auto z = std::any_cast(sprite->get_z()); 329 | auto part = *zmap[z]; 330 | part[i][no] = {f, sprite}; 331 | } 332 | } 333 | } 334 | } 335 | 336 | void Avatar::add_hairs(const std::u16string &val) 337 | { 338 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 339 | { 340 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 341 | { 342 | auto no_str = std::to_string(no); 343 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 344 | auto hairs_node = character_node->find_from_path(u"Hair/" + val + u".img/" + type); 345 | if (hairs_node != nullptr) 346 | { 347 | for (auto it : hairs_node->get_children()) 348 | { 349 | auto hairs = it.second[0]; 350 | if (hairs->type == wz::Type::UOL) 351 | { 352 | hairs = dynamic_cast *>(hairs)->get_uol(); 353 | } 354 | if (it.first == u"hairShade") 355 | { 356 | hairs = hairs->find_from_path(u"0"); 357 | } 358 | auto hair_pos = dynamic_cast *>(hairs->find_from_path(u"map/brow"))->get(); 359 | Sprite *sprite = new Sprite(hairs); 360 | Transform *f = new Transform(face_positions[i][no] - SDL_FPoint{(float)hair_pos.x, (float)hair_pos.y}); 361 | auto z = std::any_cast(sprite->get_z()); 362 | auto part = *zmap[z]; 363 | part[i][no] = {f, sprite}; 364 | } 365 | } 366 | } 367 | } 368 | } 369 | 370 | void Avatar::add_shoes(const std::u16string &val) 371 | { 372 | auto shoes_node = character_node->find_from_path(u"Shoes/" + val + u".img"); 373 | if (shoes_node != nullptr) 374 | { 375 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 376 | { 377 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 378 | { 379 | auto no_str = std::to_string(no); 380 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 381 | if (shoes_node->find_from_path(type + u"/shoes") != nullptr) 382 | { 383 | auto shoes_pos = dynamic_cast *>(shoes_node->find_from_path(type + u"/shoes/map/navel"))->get(); 384 | Sprite *sprite = new Sprite(shoes_node->find_from_path(type + u"/shoes")); 385 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)shoes_pos.x, (float)shoes_pos.y}); 386 | auto z = std::any_cast(sprite->get_z()); 387 | auto part = *zmap[z]; 388 | part[i][no] = {f, sprite}; 389 | } 390 | } 391 | } 392 | } 393 | } 394 | 395 | void Avatar::add_weapon(const std::u16string &val) 396 | { 397 | auto weapon_node = character_node->find_from_path(u"Weapon/" + val + u".img"); 398 | if (weapon_node != nullptr) 399 | { 400 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 401 | { 402 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 403 | { 404 | auto no_str = std::to_string(no); 405 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 406 | if (weapon_node->find_from_path(type + u"/weapon") != nullptr) 407 | { 408 | if (weapon_node->find_from_path(type + u"/weapon/map/hand") != nullptr) 409 | { 410 | auto weapon_pos = dynamic_cast *>(weapon_node->find_from_path(type + u"/weapon/map/hand"))->get(); 411 | Sprite *sprite = new Sprite(weapon_node->find_from_path(type + u"/weapon")); 412 | Transform *f = new Transform(arm_positions[i][no] - SDL_FPoint{(float)weapon_pos.x, (float)weapon_pos.y}); 413 | auto z = std::any_cast(sprite->get_z()); 414 | auto part = *zmap[z]; 415 | part[i][no] = {f, sprite}; 416 | } 417 | else 418 | { 419 | auto weapon_pos = dynamic_cast *>(weapon_node->find_from_path(type + u"/weapon/map/navel"))->get(); 420 | Sprite *sprite = new Sprite(weapon_node->find_from_path(type + u"/weapon")); 421 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)weapon_pos.x, (float)weapon_pos.y}); 422 | auto z = std::any_cast(sprite->get_z()); 423 | auto part = *zmap[z]; 424 | part[i][no] = {f, sprite}; 425 | } 426 | } 427 | } 428 | } 429 | } 430 | } 431 | 432 | void Avatar::add_shield(const std::u16string &val) 433 | { 434 | auto shield_node = character_node->find_from_path(u"Shield/" + val + u".img"); 435 | if (shield_node != nullptr) 436 | { 437 | for (uint8_t i = 0; i < ACTION::LENGTH; i++) 438 | { 439 | for (uint8_t no = 0; no < body_positions[i].size(); no++) 440 | { 441 | auto no_str = std::to_string(no); 442 | auto type = type_map2.at(i) + u"/" + std::u16string{no_str.begin(), no_str.end()}; 443 | if (shield_node->find_from_path(type + u"/shield") != nullptr) 444 | { 445 | auto shield_pos = dynamic_cast *>(shield_node->find_from_path(type + u"/shield/map/navel"))->get(); 446 | Sprite *sprite = new Sprite(shield_node->find_from_path(type + u"/shield")); 447 | Transform *f = new Transform(body_positions[i][no] - SDL_FPoint{(float)shield_pos.x, (float)shield_pos.y}); 448 | auto z = std::any_cast(sprite->get_z()); 449 | auto part = *zmap[z]; 450 | part[i][no] = {f, sprite}; 451 | } 452 | } 453 | } 454 | } 455 | } 456 | 457 | Avatar::~Avatar() 458 | { 459 | auto del_func = [](std::pair &pai) -> void 460 | { 461 | auto &[tr, spr] = pai; 462 | delete tr; 463 | delete spr; 464 | }; 465 | for (auto &it : body) 466 | { 467 | for (auto &[key, val] : it) 468 | { 469 | del_func(val); 470 | } 471 | } 472 | } -------------------------------------------------------------------------------- /sdlms/Components/Camera.cpp: -------------------------------------------------------------------------------- 1 | #include "Camera.h" 2 | 3 | Camera::Camera(int x, int y, float w, float h) : x(x), y(y), w(w), h(h) 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /sdlms/Components/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | #include 4 | 5 | // 6 | class Camera : public Component 7 | { 8 | public: 9 | Camera(int x, int y, float w, float h); 10 | constexpr auto get_x() { return x; } 11 | constexpr auto get_y() { return y; } 12 | constexpr auto get_w() { return w; } 13 | constexpr auto get_h() { return h; } 14 | 15 | void set_x(const int val) { x = val; } 16 | void set_y(const int val) { y = val; } 17 | void set_w(const float val) { w = val; } 18 | void set_h(const float val) { h = val; } 19 | 20 | private: 21 | int x; 22 | int y; 23 | float w; 24 | float h; 25 | }; -------------------------------------------------------------------------------- /sdlms/Components/Component.cpp: -------------------------------------------------------------------------------- 1 | #include "Component.h" 2 | 3 | Component::Component() {} 4 | Component::~Component() {} -------------------------------------------------------------------------------- /sdlms/Components/Component.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Core/World.h" 8 | 9 | class Entity; 10 | 11 | class Component 12 | { 13 | public: 14 | Component(); 15 | virtual ~Component(); 16 | int id = 0; 17 | 18 | protected: 19 | Entity *owner = nullptr; 20 | 21 | public: 22 | int get_id() const 23 | { 24 | return id; 25 | }; 26 | 27 | void set_id(int value) 28 | { 29 | id = value; 30 | }; 31 | 32 | Entity *get_owner() 33 | { 34 | return owner; 35 | }; 36 | void set_owner(Entity *value) 37 | { 38 | owner = value; 39 | }; 40 | template 41 | C *get_owner() 42 | { 43 | return dynamic_cast(owner); 44 | } 45 | 46 | template 47 | C *get_owner_component(); 48 | }; 49 | 50 | #include "Entities/Entity.h" 51 | 52 | template 53 | C *Component::get_owner_component() 54 | { 55 | return static_cast(owner->get_component()); 56 | } 57 | -------------------------------------------------------------------------------- /sdlms/Components/DistanceSprite.cpp: -------------------------------------------------------------------------------- 1 | #include "DistanceSprite.h" 2 | 3 | DistanceSprite::DistanceSprite(){} 4 | DistanceSprite::~DistanceSprite(){} 5 | 6 | void DistanceSprite::add(std::optional h, std::optional v, std::optional> disspr) 7 | { 8 | hs.push_back(h); 9 | vs.push_back(v); 10 | dissprs.push_back(disspr); 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /sdlms/Components/DistanceSprite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Components/Component.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Sprite.h" 10 | #include "AnimatedSprite.h" 11 | 12 | class DistanceSprite : public Component 13 | { 14 | private: 15 | std::vector>> dissprs; 16 | std::vector> hs; // 水平范围 17 | std::vector> vs; // 垂直范围 18 | 19 | public: 20 | DistanceSprite(); 21 | ~DistanceSprite(); 22 | void add(std::optional h, std::optional v, std::optional> disspr); 23 | constexpr auto &get_dissprs() { return dissprs; } 24 | constexpr auto &get_hs() { return hs; } 25 | constexpr auto &get_vs() { return vs; } 26 | }; 27 | -------------------------------------------------------------------------------- /sdlms/Components/HVMove.cpp: -------------------------------------------------------------------------------- 1 | #include "HVMove.h" 2 | 3 | HVMove::HVMove(int rx, int ry, bool hspeed, bool vspeed) : rx(rx), ry(ry), hspeed(hspeed), vspeed(vspeed) 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /sdlms/Components/HVMove.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | 4 | // 表示左右运动的属性 5 | class HVMove : public Component 6 | { 7 | public: 8 | HVMove(int rx, int ry, bool hspeed, bool vspeed); 9 | constexpr auto get_rx() { return rx; } 10 | constexpr auto get_ry() { return ry; } 11 | constexpr auto get_offset_x() { return offset_x; } 12 | constexpr auto get_offset_y() { return offset_y; } 13 | constexpr auto get_hspeed() { return hspeed; } 14 | constexpr auto get_vspeed() { return vspeed; } 15 | void set_offset_x(const float val) { offset_x = val; } 16 | void set_offset_y(const float val) { offset_y = val; } 17 | 18 | public: 19 | int rx; 20 | int ry; 21 | float offset_x = 0.0f; 22 | float offset_y = 0.0f; 23 | bool hspeed = false; 24 | bool vspeed = false; 25 | }; -------------------------------------------------------------------------------- /sdlms/Components/HVTile.cpp: -------------------------------------------------------------------------------- 1 | #include "HVTile.h" 2 | 3 | HVTile::HVTile(int cx, int cy, bool htile, bool vtile) : cx(cx), cy(cy), htile(htile), vtile(vtile) 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /sdlms/Components/HVTile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | 4 | // 平铺属性 5 | class HVTile : public Component 6 | { 7 | public: 8 | HVTile(int cx, int cy, bool htile, bool vtile); 9 | constexpr auto get_cx() { return cx; } 10 | constexpr auto get_cy() { return cy; } 11 | 12 | public: 13 | // 平铺间隔 14 | int cx; 15 | int cy; 16 | // 是否平铺 17 | bool htile = false; 18 | bool vtile = false; 19 | }; -------------------------------------------------------------------------------- /sdlms/Components/LimitTransform.cpp: -------------------------------------------------------------------------------- 1 | #include "LimitTransform.h" 2 | 3 | LimitTransform::LimitTransform(Transform *tr, std::optional h, std::optional v) : tr(tr), h(h), v(v) 4 | { 5 | } -------------------------------------------------------------------------------- /sdlms/Components/LimitTransform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | #include "Transform.h" 4 | #include 5 | 6 | // 限制Transform的移动范围 7 | class LimitTransform : public Component 8 | { 9 | private: 10 | std::optional h = std::nullopt; 11 | std::optional v = std::nullopt; 12 | Transform *tr = nullptr; 13 | 14 | public: 15 | LimitTransform(Transform *tr, std::optional h, std::optional v); 16 | auto &get_h() { return h; } 17 | auto &get_v() { return v; } 18 | auto &get_tr() { return tr; } 19 | }; -------------------------------------------------------------------------------- /sdlms/Components/Line.cpp: -------------------------------------------------------------------------------- 1 | #include "Line.h" 2 | #include 3 | 4 | Line::Line(SDL_FPoint m, SDL_FPoint n) : m(m), n(n) 5 | { 6 | auto [x1, y1] = m; 7 | auto [x2, y2] = n; 8 | if (x1 != x2) 9 | { 10 | // 斜线 11 | k = ((float)y2 - (float)y1) / ((float)x2 - (float)x1); 12 | intercept = y1 - k.value() * x1; 13 | } 14 | } 15 | 16 | std::optional Line::get_y(float x) 17 | { 18 | [[likely]] 19 | if (x >= get_min_x() && x <= get_max_x()) 20 | { 21 | [[likely]] 22 | if (k.has_value()) 23 | { 24 | return k.value() * x + intercept.value(); 25 | } 26 | } 27 | return std::nullopt; 28 | } 29 | 30 | std::optional Line::get_x(float y) 31 | { 32 | [[likely]] 33 | if (y >= get_min_y() && y <= get_max_y()) 34 | { 35 | [[likely]] 36 | if (k.has_value()) 37 | { 38 | return (y - intercept.value()) / k.value(); 39 | } 40 | } 41 | return std::nullopt; 42 | } 43 | -------------------------------------------------------------------------------- /sdlms/Components/Line.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | #include 4 | #include 5 | // 线 6 | class Line : public Component 7 | { 8 | public: 9 | Line(SDL_FPoint m, SDL_FPoint n); 10 | constexpr auto get_m() { return m; } 11 | constexpr auto get_n() { return n; } 12 | auto get_min_x() { return std::fmin(m.x, n.x); } 13 | auto get_max_x() { return std::fmax(m.x, n.x); } 14 | auto get_min_y() { return std::fmin(m.y, n.y); } 15 | auto get_max_y() { return std::fmax(m.y, n.y); } 16 | constexpr auto get_k() { return k; } 17 | std::optional get_y(float x); 18 | std::optional get_x(float y); 19 | 20 | private: 21 | SDL_FPoint m; 22 | SDL_FPoint n; 23 | 24 | private: 25 | std::optional k = std::nullopt; // 斜率,若k值不存在,可以判断是否是墙面 26 | std::optional intercept = std::nullopt; 27 | }; 28 | -------------------------------------------------------------------------------- /sdlms/Components/Physic/Normal.cpp: -------------------------------------------------------------------------------- 1 | #include "Normal.h" 2 | -------------------------------------------------------------------------------- /sdlms/Components/Physic/Normal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Component.h" 3 | #include 4 | 5 | // 正常物理状态,非水下,飞翔 6 | class Normal : public Component 7 | { 8 | public: 9 | Normal(){}; 10 | 11 | public: 12 | float hspeed = 0.0; 13 | std::optional hspeed_limit = SDL_FPoint{-125.0f, 125.0f}; 14 | float vspeed = 0.0; 15 | std::optional vspeed_limit = SDL_FPoint{-5000.0f, 670.0f}; 16 | float hforce = 0.0; 17 | float vforce = 0.0; 18 | float hacc = 0.0; 19 | float vacc = 0.0; 20 | enum : uint8_t 21 | { 22 | Ground, 23 | Air, 24 | Climb, 25 | }; 26 | uint8_t type = Air; 27 | 28 | enum : uint8_t 29 | { 30 | None, 31 | Up, 32 | Left, 33 | Down, 34 | Right, 35 | }; 36 | uint8_t vkey = None; // 上下按键 37 | uint8_t hkey = None; // 左右按键 38 | bool lalt = false; 39 | bool lctrl = false; 40 | }; -------------------------------------------------------------------------------- /sdlms/Components/Player.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PShocker/sdlMS/ef03334602c93e4d0e63a9ca77cad12e2dedd206/sdlms/Components/Player.cpp -------------------------------------------------------------------------------- /sdlms/Components/Player.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | 4 | class Player : public Component 5 | { 6 | public: 7 | Player(){}; 8 | }; -------------------------------------------------------------------------------- /sdlms/Components/RandomInput.cpp: -------------------------------------------------------------------------------- 1 | #include "RandomInput.h" 2 | 3 | RandomInput::RandomInput(int val) 4 | { 5 | count = std::rand() % val + 100; 6 | } -------------------------------------------------------------------------------- /sdlms/Components/RandomInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | 4 | // 随机产生按键输出组件 5 | class RandomInput : public Component 6 | { 7 | private: 8 | unsigned int count = 0; 9 | unsigned int tick = 0; 10 | 11 | public: 12 | RandomInput(int val = 60); 13 | auto get_count() { return count; }; 14 | auto get_tick() { return tick; }; 15 | void set_count(const unsigned int value) { count = value; }; 16 | void set_tick(const unsigned int value) { tick = value; }; 17 | }; -------------------------------------------------------------------------------- /sdlms/Components/RelativeTransform.cpp: -------------------------------------------------------------------------------- 1 | #include "RelativeTransform.h" 2 | 3 | RelativeTransform::RelativeTransform(Transform *tr) : tr(tr), position({0.0f, 0.0f}), rotation(0), flip(0) {} 4 | RelativeTransform::RelativeTransform(Transform *tr, SDL_FPoint p, int flip) : tr(tr), position(p), rotation(0), flip(flip) {} 5 | RelativeTransform::RelativeTransform(Transform *tr, float x, float y, int flip) : tr(tr), position({x, y}), rotation(0), flip(flip) {} 6 | RelativeTransform::~RelativeTransform() {} 7 | 8 | float RelativeTransform::get_rotation() const 9 | { 10 | return rotation; 11 | } 12 | 13 | int RelativeTransform::get_flip() const 14 | { 15 | return flip; 16 | } 17 | 18 | void RelativeTransform::set_position(const SDL_FPoint &value) 19 | { 20 | position = value; 21 | } 22 | SDL_FPoint RelativeTransform::get_position() const 23 | { 24 | return position; 25 | } 26 | 27 | void RelativeTransform::set_rotation(const float &value) 28 | { 29 | rotation = value; 30 | } 31 | 32 | void RelativeTransform::set_flip(const int value) 33 | { 34 | flip = value; 35 | } -------------------------------------------------------------------------------- /sdlms/Components/RelativeTransform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Components/Component.h" 4 | #include "Transform.h" 5 | 6 | class RelativeTransform : public Component 7 | { 8 | private: 9 | SDL_FPoint position; 10 | float rotation; 11 | int flip; 12 | Transform *tr = nullptr; 13 | 14 | public: 15 | RelativeTransform(Transform *tr); 16 | RelativeTransform(Transform *tr, SDL_FPoint p, int flip = 0); 17 | RelativeTransform(Transform *tr, float x, float y, int flip = 0); 18 | ~RelativeTransform(); 19 | 20 | SDL_FPoint get_position() const; 21 | float get_rotation() const; 22 | int get_flip() const; 23 | auto get_tr() { return tr; }; 24 | 25 | void set_position(const SDL_FPoint &value); 26 | void set_rotation(const float &value); 27 | void set_flip(const int value); 28 | void set_x(const float value) { position.x = value; }; 29 | void set_y(const float value) { position.y = value; }; 30 | }; 31 | -------------------------------------------------------------------------------- /sdlms/Components/Sound.cpp: -------------------------------------------------------------------------------- 1 | #include "Sound.h" 2 | 3 | extern "C" 4 | { 5 | #include 6 | #include 7 | #include 8 | #include 9 | } 10 | 11 | Sound *Sound::load(wz::Node *node) 12 | { 13 | // 从map缓存中获取对象 14 | if (sound_map.contains(node)) 15 | { 16 | return sound_map[node]; 17 | } 18 | else 19 | { 20 | return new Sound(node); 21 | } 22 | } 23 | 24 | Sound::Sound(wz::Node *node) 25 | { 26 | if (node != nullptr) 27 | { 28 | if (node->type == wz::Type::UOL) 29 | { 30 | node = dynamic_cast *>(node)->get_uol(); 31 | } 32 | 33 | auto sound = dynamic_cast *>(node); 34 | auto data = sound->get_raw_data(); 35 | 36 | struct buffer_data 37 | { 38 | uint8_t *ptr; 39 | size_t size; ///< size left in the buffer 40 | } bd{data.data(), data.size()}; 41 | 42 | auto avio_ctx_buffer = av_malloc(0x1000); 43 | AVIOContext *ioCtx = avio_alloc_context( 44 | (uint8_t *)avio_ctx_buffer, 0x1000, 45 | 0, &bd, 46 | [](void *opaque, uint8_t *buf, int buf_size) -> int 47 | { 48 | struct buffer_data *bd = (struct buffer_data *)opaque; 49 | buf_size = FFMIN(buf_size, bd->size); 50 | 51 | if (!buf_size) 52 | return AVERROR_EOF; 53 | 54 | /* copy internal buffer data to buf */ 55 | memcpy(buf, bd->ptr, buf_size); 56 | bd->ptr += buf_size; 57 | bd->size -= buf_size; 58 | 59 | return buf_size; 60 | }, 61 | NULL, NULL); 62 | 63 | // 打开输入文件并读取音频流信息 64 | AVFormatContext *formatContext = avformat_alloc_context(); 65 | formatContext->pb = ioCtx; 66 | 67 | if (avformat_open_input(&formatContext, nullptr, nullptr, nullptr) != 0) 68 | { 69 | // 处理打开文件失败的情况 70 | return; 71 | } 72 | if (avformat_find_stream_info(formatContext, nullptr) < 0) 73 | { 74 | // 处理找不到音频流信息的情况 75 | return; 76 | } 77 | 78 | const AVCodec *codec; 79 | int audioStreamIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0); 80 | if (audioStreamIndex == -1 || !codec) 81 | { 82 | // 打开音频解码器并分配解码上下文 83 | // 处理找不到音频流的情况 84 | return; 85 | } 86 | AVCodecParameters *codecParameters = formatContext->streams[audioStreamIndex]->codecpar; 87 | 88 | AVCodecContext *codecContext = avcodec_alloc_context3(codec); 89 | if (!codecContext) 90 | { 91 | // 处理无法分配解码上下文的情况 92 | return; 93 | } 94 | if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) 95 | { 96 | // 处理无法设置解码器参数的情况 97 | return; 98 | } 99 | if (avcodec_open2(codecContext, codec, nullptr) < 0) 100 | { 101 | // 处理无法打开解码器的情况 102 | return; 103 | } 104 | 105 | // 解码并存储PCM数据 106 | std::vector pcmData; 107 | // 解码音频帧 108 | AVPacket *packet = av_packet_alloc(); 109 | AVFrame *frame = av_frame_alloc(); 110 | 111 | SwrContext *swrContext = swr_alloc(); 112 | // 音频格式 输入的采样设置参数 113 | AVSampleFormat inFormat = codecContext->sample_fmt; 114 | // 出入的采样格式 115 | AVSampleFormat outFormat = AV_SAMPLE_FMT_S16; 116 | // 输入采样率 117 | int inSampleRate = codecContext->sample_rate; 118 | // 输出采样率 119 | int outSampleRate = inSampleRate; 120 | 121 | swr_alloc_set_opts2(&swrContext, &codecContext->ch_layout, outFormat, outSampleRate, 122 | &codecContext->ch_layout, inFormat, inSampleRate, 0, NULL); 123 | 124 | if (swr_init(swrContext) < 0) 125 | { 126 | return; 127 | } 128 | 129 | int outChannelCount = codecContext->ch_layout.nb_channels; 130 | 131 | uint8_t *out_buffer = (uint8_t *)av_malloc(2 * outSampleRate); 132 | while (av_read_frame(formatContext, packet) >= 0) 133 | { 134 | if ((avcodec_send_packet(codecContext, packet)) >= 0) 135 | { 136 | auto error = avcodec_receive_frame(codecContext, frame); 137 | if (error == AVERROR(EAGAIN) || error == AVERROR_EOF || error < 0) 138 | { 139 | return; 140 | } 141 | else if (error == 0) 142 | { 143 | swr_convert(swrContext, &out_buffer, outSampleRate * 2, 144 | (const uint8_t **)frame->data, 145 | frame->nb_samples); 146 | int size = av_samples_get_buffer_size(NULL, outChannelCount, 147 | frame->nb_samples, 148 | AV_SAMPLE_FMT_S16, 1); 149 | 150 | std::vector out(out_buffer, out_buffer + size); 151 | 152 | pcmData.insert(pcmData.end(), out.begin(), out.end()); 153 | 154 | av_frame_unref(frame); 155 | } 156 | av_packet_unref(packet); 157 | } 158 | } 159 | av_freep(&out_buffer); 160 | 161 | av_frame_free(&frame); 162 | av_packet_free(&packet); 163 | 164 | swr_free(&swrContext); 165 | 166 | avcodec_free_context(&codecContext); 167 | avformat_close_input(&formatContext); 168 | 169 | pcm_data = pcmData; 170 | freq = outSampleRate; 171 | offset = 0; 172 | delay = 0; 173 | sound_map[node] = this; 174 | } 175 | } -------------------------------------------------------------------------------- /sdlms/Components/Sound.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | #include "wz/Property.hpp" 4 | 5 | class Sound : public Component 6 | { 7 | public: 8 | static Sound *load(wz::Node *node); 9 | static inline std::map sound_map; 10 | 11 | private: 12 | Sound(wz::Node *node); 13 | Sound(){}; 14 | 15 | public: 16 | constexpr auto get_pcm_data() { return &pcm_data; } 17 | constexpr auto get_freq() { return freq; } 18 | constexpr auto get_offset() { return offset; } 19 | constexpr auto get_delay() { return delay; } 20 | constexpr auto get_play() { return play; } 21 | 22 | void set_offset(unsigned int val) { offset = val; } 23 | void set_play(bool val) { play = val; } 24 | 25 | public: 26 | std::vector pcm_data; 27 | unsigned int freq; 28 | unsigned int offset; // 记录当前播放的位置 29 | unsigned int delay; // 播放声音后下次播放的间隔,若为-1,则表示播放1次 30 | bool play = false; // 当前是否播放 31 | }; 32 | -------------------------------------------------------------------------------- /sdlms/Components/Sprite.cpp: -------------------------------------------------------------------------------- 1 | #include "Sprite.h" 2 | #include "Core/Window.h" 3 | 4 | Sprite::Sprite(wz::Node *node, int alpha) 5 | { 6 | if (node->type == wz::Type::UOL) 7 | { 8 | node = dynamic_cast *>(node)->get_uol(); 9 | } 10 | 11 | auto canvas = dynamic_cast *>(node); 12 | height = canvas->get().height; 13 | width = canvas->get().width; 14 | 15 | auto raw_data = canvas->get_raw_data(); 16 | auto format = canvas->get().format + canvas->get().format2; 17 | 18 | auto o = dynamic_cast *>(canvas->get_child(u"origin")); 19 | 20 | auto ox = 0; 21 | auto oy = 0; 22 | 23 | if (o != nullptr) 24 | { 25 | ox = o->get().x; 26 | oy = o->get().y; 27 | } 28 | origin = {ox, oy}; 29 | 30 | delay = 100; 31 | 32 | if (node->get_child(u"delay") != nullptr) 33 | { 34 | if (node->get_child(u"delay")->type == wz::Type::String) 35 | { 36 | auto delay_str = dynamic_cast *>(node->get_child(u"delay"))->get(); 37 | delay = std::stoi(std::string{delay_str.begin(), delay_str.end()}); 38 | } 39 | else if (node->get_child(u"delay")->type == wz::Type::Int) 40 | { 41 | delay = dynamic_cast *>(node->get_child(u"delay"))->get(); 42 | } 43 | } 44 | 45 | if (canvas->get_child(u"a0") != nullptr && canvas->get_child(u"a1") != nullptr) 46 | { 47 | if (canvas->get_child(u"a0")->type == wz::Type::Int) 48 | { 49 | 50 | a0 = dynamic_cast *>(canvas->get_child(u"a0"))->get(); 51 | } 52 | else 53 | { 54 | auto a0_str = dynamic_cast *>(node->get_child(u"a0"))->get(); 55 | a0 = std::stoi(std::string{a0_str.begin(), a0_str.end()}); 56 | } 57 | if (canvas->get_child(u"a1")->type == wz::Type::Int) 58 | { 59 | a1 = dynamic_cast *>(canvas->get_child(u"a1"))->get(); 60 | } 61 | else 62 | { 63 | auto a1_str = dynamic_cast *>(node->get_child(u"a1"))->get(); 64 | a1 = std::stoi(std::string{a1_str.begin(), a1_str.end()}); 65 | } 66 | } 67 | a0 = a0 * ((float)alpha / 255); 68 | a1 = a1 * ((float)alpha / 255); 69 | 70 | if (canvas->get_child(u"z") != nullptr) 71 | { 72 | if (canvas->get_child(u"z")->type == wz::Type::Int) 73 | { 74 | z = dynamic_cast *>(canvas->get_child(u"z"))->get(); 75 | } 76 | else if (canvas->get_child(u"z")->type == wz::Type::String) 77 | { 78 | z = dynamic_cast *>(canvas->get_child(u"z"))->get(); 79 | } 80 | } 81 | 82 | // 图片原始数据,部分格式需要转换 83 | std::vector pixel; 84 | 85 | switch (format) 86 | { 87 | case 1: 88 | { 89 | pixel = raw_data; 90 | format = SDL_PIXELFORMAT_ARGB4444; 91 | texture = SDL_CreateTexture(Window::get_renderer(), format, SDL_TEXTUREACCESS_STATIC, width, height); 92 | SDL_UpdateTexture(texture, NULL, pixel.data(), width * sizeof(Uint16)); 93 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 94 | break; 95 | } 96 | case 2: 97 | { 98 | pixel = raw_data; 99 | format = SDL_PIXELFORMAT_ARGB8888; 100 | texture = SDL_CreateTexture(Window::get_renderer(), format, SDL_TEXTUREACCESS_STATIC, width, height); 101 | SDL_UpdateTexture(texture, NULL, pixel.data(), width * sizeof(Uint32)); 102 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 103 | break; 104 | } 105 | case 517: // rgb565压缩缩略图 106 | { 107 | pixel.resize(width * height * 2, 0); 108 | int lineIndex = 0; 109 | for (int j0 = 0, j1 = height / 16; j0 < j1; j0++) 110 | { 111 | int dstIndex = lineIndex; 112 | for (int i0 = 0, i1 = width / 16; i0 < i1; i0++) 113 | { 114 | int idx = (i0 + j0 * i1) * 2; 115 | unsigned char b0 = raw_data[idx]; 116 | unsigned char b1 = raw_data[idx + 1]; 117 | for (int k = 0; k < 16; k++) 118 | { 119 | pixel[dstIndex++] = b0; 120 | pixel[dstIndex++] = b1; 121 | } 122 | } 123 | for (int k = 1; k < 16; k++) 124 | { 125 | for (int m = 0; m < width * 2; m++) 126 | { 127 | pixel[dstIndex + m] = pixel[lineIndex + m]; 128 | } 129 | dstIndex += width * 2; 130 | } 131 | lineIndex += width * 32; 132 | } 133 | 134 | format = SDL_PIXELFORMAT_RGB565; 135 | texture = SDL_CreateTexture(Window::get_renderer(), format, SDL_TEXTUREACCESS_STATIC, width, height); 136 | SDL_UpdateTexture(texture, NULL, pixel.data(), width * sizeof(Uint16)); 137 | break; 138 | } 139 | default: 140 | { 141 | break; 142 | } 143 | } 144 | } 145 | 146 | Sprite::Sprite(wz::Node *node, int width, int height, uint8_t type) 147 | { 148 | switch (type) 149 | { 150 | case NameTag: 151 | { 152 | auto w = dynamic_cast *>(node->find_from_path(u"w")); 153 | auto e = dynamic_cast *>(node->find_from_path(u"e")); 154 | auto c = dynamic_cast *>(node->find_from_path(u"c")); 155 | 156 | width = width + w->get().width + e->get().width; 157 | height = std::max(height, w->get().height); 158 | texture = SDL_CreateTexture(Window::get_renderer(), SDL_PIXELFORMAT_ARGB4444, SDL_TEXTUREACCESS_STATIC, width, height); 159 | 160 | SDL_Rect rect{0, 0, w->get().width, w->get().height}; 161 | SDL_UpdateTexture(texture, &rect, w->get_raw_data().data(), w->get().width * sizeof(Uint16)); 162 | 163 | for (int i = 0; i <= (width - w->get().width - e->get().width) / c->get().width; i++) 164 | { 165 | rect = {w->get().width + i * c->get().width, 0, c->get().width, c->get().height}; 166 | SDL_UpdateTexture(texture, &rect, c->get_raw_data().data(), c->get().width * sizeof(Uint16)); 167 | } 168 | rect = {width - e->get().width, 0, e->get().width, e->get().height}; 169 | SDL_UpdateTexture(texture, &rect, e->get_raw_data().data(), e->get().width * sizeof(Uint16)); 170 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 171 | this->width = width; 172 | this->height = height; 173 | break; 174 | } 175 | case ChatBallon: 176 | { 177 | auto c = dynamic_cast *>(node->find_from_path(u"c")); 178 | auto e = dynamic_cast *>(node->find_from_path(u"e")); 179 | auto ne = dynamic_cast *>(node->find_from_path(u"ne")); 180 | auto n = dynamic_cast *>(node->find_from_path(u"n")); 181 | auto nw = dynamic_cast *>(node->find_from_path(u"nw")); 182 | auto w = dynamic_cast *>(node->find_from_path(u"w")); 183 | auto sw = dynamic_cast *>(node->find_from_path(u"sw")); 184 | auto s = dynamic_cast *>(node->find_from_path(u"s")); 185 | auto se = dynamic_cast *>(node->find_from_path(u"se")); 186 | auto arrow = dynamic_cast *>(node->find_from_path(u"arrow")); 187 | 188 | width += nw->get().width + ne->get().width; 189 | 190 | height += nw->get().height + sw->get().height; 191 | auto line = std::ceil((float)height / (float)c->get().height); 192 | height = line * c->get().height; 193 | 194 | texture = SDL_CreateTexture(Window::get_renderer(), SDL_PIXELFORMAT_ARGB4444, SDL_TEXTUREACCESS_STATIC, width, height + 8); 195 | SDL_Rect rect; 196 | 197 | for (int x = 0; x <= width; x += c->get().width) 198 | { 199 | for (int y = 0; y <= height - c->get().height; y += c->get().height) 200 | { 201 | rect = {x, y, c->get().width, c->get().height}; 202 | SDL_UpdateTexture(texture, &rect, c->get_raw_data().data(), c->get().width * sizeof(Uint16)); 203 | } 204 | } 205 | 206 | for (int i = nw->get().height; i <= height - w->get().height; i += w->get().height) 207 | { 208 | rect = {0, i, w->get().width, w->get().height}; 209 | SDL_UpdateTexture(texture, &rect, w->get_raw_data().data(), w->get().width * sizeof(Uint16)); 210 | 211 | rect = {width - e->get().width, i, e->get().width, e->get().height}; 212 | SDL_UpdateTexture(texture, &rect, e->get_raw_data().data(), e->get().width * sizeof(Uint16)); 213 | } 214 | 215 | for (int i = 0; i <= width; i += n->get().width) 216 | { 217 | rect = {i, 0, n->get().width, n->get().height}; 218 | SDL_UpdateTexture(texture, &rect, n->get_raw_data().data(), n->get().width * sizeof(Uint16)); 219 | 220 | rect = {i, height - s->get().height, s->get().width, s->get().height}; 221 | SDL_UpdateTexture(texture, &rect, s->get_raw_data().data(), s->get().width * sizeof(Uint16)); 222 | } 223 | 224 | rect = {0, nw->get().height, w->get().width, w->get().height}; 225 | SDL_UpdateTexture(texture, &rect, w->get_raw_data().data(), w->get().width * sizeof(Uint16)); 226 | 227 | rect = {0, height - sw->get().height - w->get().height, w->get().width, w->get().height}; 228 | SDL_UpdateTexture(texture, &rect, w->get_raw_data().data(), w->get().width * sizeof(Uint16)); 229 | 230 | rect = {width - e->get().width, nw->get().height, e->get().width, e->get().height}; 231 | SDL_UpdateTexture(texture, &rect, e->get_raw_data().data(), e->get().width * sizeof(Uint16)); 232 | 233 | rect = {width - e->get().width, height - sw->get().height - e->get().height, e->get().width, e->get().height}; 234 | SDL_UpdateTexture(texture, &rect, e->get_raw_data().data(), e->get().width * sizeof(Uint16)); 235 | 236 | rect = {0, 0, nw->get().width, nw->get().height}; 237 | SDL_UpdateTexture(texture, &rect, nw->get_raw_data().data(), nw->get().width * sizeof(Uint16)); 238 | 239 | rect = {0, height - sw->get().height, sw->get().width, sw->get().height}; 240 | SDL_UpdateTexture(texture, &rect, sw->get_raw_data().data(), sw->get().width * sizeof(Uint16)); 241 | 242 | rect = {width - ne->get().width, 0, ne->get().width, ne->get().height}; 243 | SDL_UpdateTexture(texture, &rect, ne->get_raw_data().data(), ne->get().width * sizeof(Uint16)); 244 | 245 | rect = {width - se->get().width, height - se->get().height, se->get().width, se->get().height}; 246 | SDL_UpdateTexture(texture, &rect, se->get_raw_data().data(), se->get().width * sizeof(Uint16)); 247 | 248 | rect = {width / 2 - arrow->get().width / 2, height - arrow->get().height + 8, arrow->get().width - 1, arrow->get().height}; 249 | SDL_UpdateTexture(texture, &rect, arrow->get_raw_data().data() + 2, arrow->get().width * sizeof(Uint16)); 250 | 251 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 252 | this->width = width; 253 | this->height = height; 254 | break; 255 | } 256 | default: 257 | break; 258 | } 259 | } 260 | 261 | Sprite::Sprite(SDL_Texture *texture, int w, int h) : texture(texture), width(w), height(h) 262 | { 263 | } 264 | 265 | Sprite::~Sprite() 266 | { 267 | SDL_DestroyTexture(texture); 268 | } 269 | -------------------------------------------------------------------------------- /sdlms/Components/Sprite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "wz/Property.hpp" 9 | #include "Component.h" 10 | 11 | class Sprite : public Component 12 | { 13 | public: 14 | Sprite(SDL_Texture *texture, int w, int h); 15 | Sprite(wz::Node *node, int width, int height, uint8_t type); 16 | Sprite(wz::Node *node, int alpha = 255); 17 | ~Sprite(); 18 | 19 | enum Type : uint8_t 20 | { 21 | NameTag, 22 | ChatBallon, 23 | }; 24 | 25 | private: 26 | Sprite(){}; 27 | 28 | public: 29 | const auto get_width() { return width; } 30 | const auto get_height() { return height; } 31 | SDL_Texture *get_texture() { return texture; } 32 | 33 | const auto get_delay() { return delay; } 34 | const auto get_a0() { return a0; } 35 | const auto get_a1() { return a1; } 36 | const auto get_origin() { return origin; } 37 | 38 | const auto get_z() { return z; } 39 | 40 | public: 41 | SDL_Texture *texture = nullptr; 42 | int width = 0; 43 | int height = 0; 44 | 45 | int delay = 0; 46 | int a0 = 255; 47 | int a1 = 255; 48 | SDL_Point origin = {0, 0}; 49 | 50 | std::any z = 0; 51 | }; -------------------------------------------------------------------------------- /sdlms/Components/Transform.cpp: -------------------------------------------------------------------------------- 1 | #include "Transform.h" 2 | 3 | Transform::Transform() : position({0, 0}), rotation(0), flip(0) {} 4 | Transform::Transform(SDL_FPoint p, int flip, bool camera) : position(p), rotation(0), flip(0) {} 5 | Transform::Transform(float x, float y, int flip, bool camera) : position({x, y}), rotation(0), flip(flip), camera(camera) {} 6 | Transform::~Transform() {} 7 | 8 | float Transform::get_rotation() const 9 | { 10 | return rotation; 11 | } 12 | 13 | int Transform::get_flip() const 14 | { 15 | return flip; 16 | } 17 | 18 | void Transform::set_position(const SDL_FPoint &value) 19 | { 20 | position = value; 21 | } 22 | SDL_FPoint Transform::get_position() const 23 | { 24 | return position; 25 | } 26 | 27 | void Transform::set_rotation(const float &value) 28 | { 29 | rotation = value; 30 | } 31 | 32 | void Transform::set_flip(const int value) 33 | { 34 | flip = value; 35 | } 36 | -------------------------------------------------------------------------------- /sdlms/Components/Transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Components/Component.h" 4 | 5 | class Transform : public Component 6 | { 7 | private: 8 | SDL_FPoint position = {0, 0}; 9 | float rotation = 0; 10 | int flip = 0; 11 | bool camera = false; 12 | 13 | public: 14 | Transform(); 15 | Transform(SDL_FPoint p, int flip = 0, bool camera = false); 16 | Transform(float x, float y, int flip = 0, bool camera = false); 17 | ~Transform(); 18 | 19 | SDL_FPoint get_position() const; 20 | float get_rotation() const; 21 | int get_flip() const; 22 | auto get_camera() { return camera; }; 23 | 24 | void set_position(const SDL_FPoint &value); 25 | void set_rotation(const float &value); 26 | void set_flip(const int value); 27 | void set_x(const float value) { position.x = value; }; 28 | void set_y(const float value) { position.y = value; }; 29 | }; 30 | -------------------------------------------------------------------------------- /sdlms/Components/Video.cpp: -------------------------------------------------------------------------------- 1 | #include "Video.h" 2 | #include "Core/Window.h" 3 | #include 4 | 5 | Video *Video::load(const std::string &url, int width, int height) 6 | { 7 | if (!inited) 8 | { 9 | // 初始化FFmpeg 10 | avformat_network_init(); 11 | inited = true; 12 | } 13 | // 打开视频文件 14 | AVFormatContext *formatContext = avformat_alloc_context(); 15 | if (avformat_open_input(&formatContext, url.c_str(), NULL, NULL) != 0) 16 | { 17 | return nullptr; 18 | } 19 | if (avformat_find_stream_info(formatContext, NULL) < 0) 20 | { 21 | return nullptr; 22 | } 23 | const AVCodec *codec; 24 | int videoStreamIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0); 25 | if (videoStreamIndex == -1 || !codec) 26 | { 27 | return nullptr; 28 | } 29 | AVCodecParameters *codecParameters = formatContext->streams[videoStreamIndex]->codecpar; 30 | AVCodecContext *codecContext = avcodec_alloc_context3(codec); 31 | if (!codecContext) 32 | { 33 | return nullptr; 34 | } 35 | if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) 36 | { 37 | return nullptr; 38 | } 39 | // 设置解码线程 40 | codecContext->thread_count = std::thread::hardware_concurrency(); 41 | 42 | if (avcodec_open2(codecContext, codec, nullptr) < 0) 43 | { 44 | return nullptr; 45 | } 46 | 47 | struct SwsContext *swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt, 48 | codecContext->width, codecContext->height, AV_PIX_FMT_YUV420P, 49 | SWS_BICUBIC, NULL, NULL, NULL); 50 | 51 | return new Video(formatContext, codecContext, videoStreamIndex, swsContext, width, height); 52 | } 53 | 54 | Video::Video(AVFormatContext *formatContext, AVCodecContext *codecContext, int videoStreamIndex, SwsContext *swsContext, int width, int height) : formatContext(formatContext), 55 | codecContext(codecContext), 56 | videoStreamIndex(videoStreamIndex), 57 | swsContext(swsContext), 58 | width(width), 59 | height(height) 60 | 61 | { 62 | texture = SDL_CreateTexture(Window::get_renderer(), SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, 63 | codecContext->width, codecContext->height); 64 | } 65 | -------------------------------------------------------------------------------- /sdlms/Components/Video.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Component.h" 3 | #include 4 | 5 | extern "C" 6 | { 7 | #include 8 | #include 9 | #include 10 | } 11 | 12 | // 视频组件,可以是本地视频或者网络(直播)视频 13 | class Video : public Component 14 | { 15 | public: 16 | static Video *load(const std::string &url, int width, int height); 17 | static inline bool inited = false; 18 | 19 | public: 20 | const auto get_width() { return width; } 21 | const auto get_height() { return height; } 22 | 23 | public: 24 | SDL_Texture *texture; 25 | int width; 26 | int height; 27 | 28 | public: 29 | Video(AVFormatContext *formatContext, AVCodecContext *codecContext, int videoStreamIndex, SwsContext *swsContext, int width, int height); 30 | AVFormatContext *formatContext; 31 | AVCodecContext *codecContext; 32 | int videoStreamIndex; 33 | SwsContext *swsContext; 34 | }; -------------------------------------------------------------------------------- /sdlms/Core/ECSSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define __ECS_GREEN "\033[0;32m" 6 | #define __ECS_RED "\033[0;31m" 7 | #define __ECS_YELLOW "\033[1;33m" 8 | #define __ECS_RESET "\033[0m" 9 | 10 | #define ECS_PRINT(Fmt, ...) std::fprintf(stdout, __ECS_RESET "[" __ECS_GREEN "ECS" __ECS_RESET "] " Fmt "\n", __VA_ARGS__) 11 | #define ECS_PRINT_WARNING(Fmt, ...) std::fprintf(stderr, __ECS_RESET "[" __ECS_GREEN "ECS" __ECS_RESET "] " __ECS_YELLOW "WARNING: " Fmt __ECS_RESET "\n", __VA_ARGS__) 12 | #define ECS_PRINT_ERROR(Fmt, ...) std::fprintf(stderr, __ECS_RESET "[" __ECS_GREEN "ECS" __ECS_RESET "] " __ECS_RED "ERROR: " Fmt __ECS_RESET "\n", __VA_ARGS__) 13 | 14 | #ifdef ECS_DEBUG 15 | #define DEBUG_PRINT(Fmt, ...) ECS_PRINT(Fmt, __VA_ARGS__) 16 | #else 17 | #define DEBUG_PRINT(Fmt, ...) 18 | #endif 19 | -------------------------------------------------------------------------------- /sdlms/Core/File.cpp: -------------------------------------------------------------------------------- 1 | #include "File.h" 2 | 3 | unsigned char *File::buffer(const char *path) 4 | { 5 | SDL_RWops *rw = SDL_RWFromFile(path, "rb"); 6 | if (rw == NULL) 7 | { 8 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open file: %s", SDL_GetError()); 9 | return nullptr; 10 | } 11 | 12 | // 获取文件大小 13 | Sint64 file_size = SDL_RWsize(rw); 14 | if (file_size < 0) 15 | { 16 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't get file size: %s", SDL_GetError()); 17 | SDL_RWclose(rw); 18 | return nullptr; 19 | } 20 | // 分配缓冲区来存储文件内容 21 | unsigned char *buffer = (unsigned char *)malloc(file_size); 22 | if (buffer == NULL) 23 | { 24 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory"); 25 | SDL_RWclose(rw); 26 | return nullptr; 27 | } 28 | // 读取文件内容到缓冲区 29 | size_t read = SDL_RWread(rw, buffer, 1, file_size); 30 | if (read != file_size) 31 | { 32 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read entire file: %s", SDL_GetError()); 33 | free(buffer); 34 | SDL_RWclose(rw); 35 | return nullptr; 36 | } 37 | SDL_RWclose(rw); 38 | return buffer; 39 | } 40 | 41 | unsigned int File::size(const char *path) 42 | { 43 | SDL_RWops *rw = SDL_RWFromFile(path, "rb"); 44 | if (rw == NULL) 45 | { 46 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open file: %s", SDL_GetError()); 47 | return 0; 48 | } 49 | 50 | // 获取文件大小 51 | auto size = SDL_RWsize(rw); 52 | SDL_RWclose(rw); 53 | return size; 54 | } -------------------------------------------------------------------------------- /sdlms/Core/File.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class File{ 5 | public: 6 | static unsigned char *buffer(const char *path); 7 | static unsigned int size(const char *path); 8 | }; -------------------------------------------------------------------------------- /sdlms/Core/FreeType.cpp: -------------------------------------------------------------------------------- 1 | #include "FreeType.h" 2 | 3 | void FreeType::init(const std::string &filename_prefix) 4 | { 5 | library = new FT_Library{}; 6 | FT_Init_FreeType(library); 7 | // 加载字体文件 8 | face = new FT_Face{}; 9 | #ifdef __WIN32__ 10 | FT_New_Face(*library, "C:/Windows/Fonts/simsun.ttc", 0, face); 11 | #else 12 | FT_New_Face(*library, (filename_prefix + "simsun.ttc").c_str(), 0, face); 13 | #endif 14 | FT_Select_Charmap(*face, FT_ENCODING_UNICODE); 15 | // 设置字体大小18 16 | FT_Set_Pixel_Sizes(*face, 0, 18); 17 | return; 18 | } 19 | 20 | void FreeType::size(int size) 21 | { 22 | FT_Set_Pixel_Sizes(*face, 0, size); 23 | } 24 | 25 | Sprite *FreeType::str(const std::u16string &s, SDL_Color color, int w) 26 | { 27 | SDL_Renderer *renderer = Window::get_renderer(); 28 | 29 | FT_GlyphSlot glyph_slot = (*face)->glyph; 30 | // 计算每个字符的位置和大小 31 | int width = 0; 32 | int height = 0; 33 | for (int i = 0; i < s.length(); i++) 34 | { 35 | auto c = s[i]; 36 | auto index = FT_Get_Char_Index(*face, c); 37 | FT_Load_Glyph(*face, index, FT_LOAD_DEFAULT); 38 | if (w <= 0 || (w > 0 && i < w)) 39 | { 40 | width += glyph_slot->advance.x >> 6; 41 | } 42 | height = std::max((int)glyph_slot->bitmap.rows, height); 43 | } 44 | if (w <= 0) 45 | { 46 | SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); 47 | int offsetX = 0; 48 | for (auto &c : s) 49 | { 50 | auto index = FT_Get_Char_Index(*face, c); 51 | FT_Load_Glyph(*face, index, FT_LOAD_DEFAULT); 52 | FT_Render_Glyph(glyph_slot, FT_RENDER_MODE_MONO); 53 | auto bitmap = glyph_slot->bitmap; 54 | // 默认顶部对齐 55 | SDL_Rect char_rect = {offsetX, (int)(height - glyph_slot->bitmap.rows) / 2, (int)glyph_slot->bitmap.width, (int)glyph_slot->bitmap.rows}; 56 | // 特殊符号居中 57 | if (c == u'<' || c == u'>') 58 | { 59 | char_rect.y = (height - glyph_slot->bitmap.rows) / 2; 60 | } 61 | // 转换为ARGB8888格式 62 | unsigned char *argb_data = new unsigned char[bitmap.width * bitmap.rows * 4]; 63 | for (int y = 0; y < bitmap.rows; y++) 64 | { 65 | for (int x = 0; x < bitmap.width; x++) 66 | { 67 | unsigned char value = bitmap.buffer[y * bitmap.pitch + (x >> 3)] & (0x80 >> (x & 7)); 68 | [[likely]] 69 | if (value == 0) 70 | { 71 | argb_data[(y * bitmap.width + x) * 4] = 0; // B 72 | argb_data[(y * bitmap.width + x) * 4 + 1] = 0; // G 73 | argb_data[(y * bitmap.width + x) * 4 + 2] = 0; // R 74 | argb_data[(y * bitmap.width + x) * 4 + 3] = 0; // A 75 | } 76 | else 77 | { 78 | argb_data[(y * bitmap.width + x) * 4] = color.b; // B 79 | argb_data[(y * bitmap.width + x) * 4 + 1] = color.g; // G 80 | argb_data[(y * bitmap.width + x) * 4 + 2] = color.r; // R 81 | argb_data[(y * bitmap.width + x) * 4 + 3] = color.a; // A 82 | } 83 | } 84 | } 85 | SDL_UpdateTexture(texture, &char_rect, argb_data, bitmap.width * sizeof(Uint32)); 86 | offsetX += glyph_slot->advance.x >> 6; 87 | delete[] argb_data; 88 | } 89 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 90 | return new Sprite(texture, width, height); 91 | } 92 | else 93 | { 94 | auto length = s.length(); 95 | auto line = std::ceil((float)length / (float)w); 96 | int offsetX = 0; 97 | int offsetY = 0; 98 | height += 6; 99 | width += 12; 100 | SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height * line); 101 | for (int i = 0; i < s.length(); i++) 102 | { 103 | // 获取第l行数 104 | auto l = i / w + 1; 105 | if (i % w == 0) 106 | { 107 | offsetX = 0; 108 | } 109 | offsetY = (l - 1) * height; 110 | auto &c = s[i]; 111 | auto index = FT_Get_Char_Index(*face, c); 112 | FT_Load_Glyph(*face, index, FT_LOAD_DEFAULT); 113 | FT_Render_Glyph(glyph_slot, FT_RENDER_MODE_MONO); 114 | auto bitmap = glyph_slot->bitmap; 115 | // 默认顶部对齐 116 | SDL_Rect char_rect = {offsetX, (int)(height - glyph_slot->bitmap.rows) / 2 + offsetY, (int)glyph_slot->bitmap.width, (int)glyph_slot->bitmap.rows}; 117 | // 特殊符号居中 118 | if (c == u'<' || c == u'>') 119 | { 120 | char_rect.y = (height - glyph_slot->bitmap.rows) / 2; 121 | } 122 | // 转换为ARGB8888格式 123 | unsigned char *argb_data = new unsigned char[bitmap.width * bitmap.rows * 4]; 124 | for (int y = 0; y < bitmap.rows; y++) 125 | { 126 | for (int x = 0; x < bitmap.width; x++) 127 | { 128 | unsigned char value = bitmap.buffer[y * bitmap.pitch + (x >> 3)] & (0x80 >> (x & 7)); 129 | [[likely]] 130 | if (value == 0) 131 | { 132 | argb_data[(y * bitmap.width + x) * 4] = 0; // B 133 | argb_data[(y * bitmap.width + x) * 4 + 1] = 0; // G 134 | argb_data[(y * bitmap.width + x) * 4 + 2] = 0; // R 135 | argb_data[(y * bitmap.width + x) * 4 + 3] = 0; // A 136 | } 137 | else 138 | { 139 | argb_data[(y * bitmap.width + x) * 4] = color.b; // B 140 | argb_data[(y * bitmap.width + x) * 4 + 1] = color.g; // G 141 | argb_data[(y * bitmap.width + x) * 4 + 2] = color.r; // R 142 | argb_data[(y * bitmap.width + x) * 4 + 3] = color.a; // A 143 | } 144 | } 145 | } 146 | SDL_UpdateTexture(texture, &char_rect, argb_data, bitmap.width * sizeof(Uint32)); 147 | offsetX += glyph_slot->advance.x >> 6; 148 | delete[] argb_data; 149 | } 150 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 151 | return new Sprite(texture, width, height * line); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /sdlms/Core/FreeType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include FT_FREETYPE_H 4 | 5 | #include "Components/Sprite.h" 6 | 7 | class FreeType 8 | { 9 | public: 10 | static void init(const std::string &filename_prefix = ""); 11 | static void size(int size); 12 | static inline FT_Library *library; 13 | static inline FT_Face *face; 14 | static Sprite *str(const std::u16string &s, SDL_Color color = {255, 255, 255, 255}, int w = 0); 15 | }; -------------------------------------------------------------------------------- /sdlms/Core/Input.cpp: -------------------------------------------------------------------------------- 1 | #include "Input.h" 2 | 3 | #include "Core/ECSSystem.h" 4 | 5 | std::unordered_set Input::pressed_keys = {}; 6 | std::unordered_set Input::pressed_keys_momentary = {}; 7 | std::unordered_set Input::released_keys_momentary = {}; 8 | 9 | std::unordered_set Input::pressed_mouse = {}; 10 | std::unordered_set Input::pressed_mouse_momentary = {}; 11 | std::unordered_set Input::released_mouse_momentary = {}; 12 | 13 | bool Input::is_key_held(SDL_Keycode key) 14 | { 15 | return pressed_keys.contains(key); 16 | } 17 | 18 | bool Input::is_key_pressed(SDL_Keycode key) 19 | { 20 | return pressed_keys_momentary.contains(key); 21 | } 22 | 23 | bool Input::is_key_released(SDL_Keycode key) 24 | { 25 | return released_keys_momentary.contains(key); 26 | } 27 | 28 | bool Input::is_mouse_button_held(MouseButton button) 29 | { 30 | return pressed_mouse.contains(button); 31 | } 32 | 33 | bool Input::is_mouse_button_pressed(MouseButton button) 34 | { 35 | return pressed_mouse_momentary.contains(button); 36 | } 37 | 38 | bool Input::is_mouse_button_released(MouseButton button) 39 | { 40 | return released_mouse_momentary.contains(button); 41 | } 42 | 43 | void Input::process_input_event(EventType type, const SDL_Event &event) 44 | { 45 | switch (type) 46 | { 47 | case EventType::KeyPressed: 48 | { 49 | pressed_keys.insert(event.key.keysym.sym); 50 | pressed_keys_momentary.insert(event.key.keysym.sym); 51 | } 52 | break; 53 | 54 | case EventType::KeyReleased: 55 | { 56 | pressed_keys.erase(event.key.keysym.sym); 57 | released_keys_momentary.insert(event.key.keysym.sym); 58 | } 59 | break; 60 | 61 | case EventType::MousePressed: 62 | { 63 | pressed_mouse.insert(static_cast(event.button.button)); 64 | pressed_mouse_momentary.insert(static_cast(event.button.button)); 65 | } 66 | break; 67 | 68 | case EventType::MouseReleased: 69 | { 70 | pressed_mouse.erase(static_cast(event.button.button)); 71 | released_mouse_momentary.insert(static_cast(event.button.button)); 72 | } 73 | break; 74 | } 75 | } 76 | 77 | void Input::update_momentary_keys() 78 | { 79 | pressed_keys_momentary.clear(); 80 | released_keys_momentary.clear(); 81 | pressed_mouse_momentary.clear(); 82 | released_mouse_momentary.clear(); 83 | } 84 | -------------------------------------------------------------------------------- /sdlms/Core/Input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class Input { 10 | public: 11 | enum class MouseButton { ButtonLeft = 1, ButtonMiddle = 2, ButtonRight = 3 }; 12 | 13 | private: 14 | static std::unordered_set pressed_keys; 15 | static std::unordered_set pressed_keys_momentary; 16 | static std::unordered_set released_keys_momentary; 17 | 18 | static std::unordered_set pressed_mouse; 19 | static std::unordered_set pressed_mouse_momentary; 20 | static std::unordered_set released_mouse_momentary; 21 | 22 | public: 23 | enum class EventType { KeyPressed, KeyReleased, MousePressed, MouseReleased }; 24 | 25 | static bool is_key_pressed(SDL_Keycode key); 26 | static bool is_key_held(SDL_Keycode key); 27 | static bool is_key_released(SDL_Keycode key); 28 | 29 | static bool is_mouse_button_pressed(MouseButton button); 30 | static bool is_mouse_button_held(MouseButton button); 31 | static bool is_mouse_button_released(MouseButton button); 32 | 33 | static void process_input_event(EventType type, const SDL_Event& event); 34 | 35 | static void update_momentary_keys(); 36 | }; 37 | -------------------------------------------------------------------------------- /sdlms/Core/Map.cpp: -------------------------------------------------------------------------------- 1 | #include "Map.h" 2 | #include "Entities/Tile.h" 3 | #include "Entities/Obj.h" 4 | #include "Entities/BackGround.h" 5 | #include "Entities/FootHold.h" 6 | #include "Entities/Npc.h" 7 | #include "Entities/Mob.h" 8 | #include "Entities/Border.h" 9 | #include "Entities/LadderRope.h" 10 | #include "Entities/Portal.h" 11 | #include "Resource/Wz.h" 12 | #include "Components/Line.h" 13 | #include "Components/Transform.h" 14 | 15 | void Map::load(int map_id, World *world) 16 | { 17 | 18 | clean_up(world); 19 | auto node = load_map_node(map_id, world); 20 | load_tile(node, world); 21 | load_obj(node, world); 22 | load_background(node, world); 23 | load_foothold(node, world); 24 | load_life(node, world); 25 | load_border(node, world); 26 | load_ladderRope(node, world); 27 | load_portal(node, world); 28 | load_bgm(node, world); 29 | set_map_id(map_id); 30 | // load_string(map_id); 31 | } 32 | 33 | void Map::load_obj(wz::Node *node, World *world) 34 | { 35 | auto _node = node; 36 | for (size_t i = 0; i < 8; i++) 37 | { 38 | node = _node->get_child(std::to_string(i)); 39 | 40 | for (auto &[key, val] : node->get_child(u"obj")->get_children()) 41 | { 42 | auto id = std::stoi(std::string{key.begin(), key.end()}); 43 | Obj *obj = new Obj(val[0], id, i, world); 44 | world->add_entity(obj); 45 | } 46 | } 47 | } 48 | 49 | void Map::load_tile(wz::Node *node, World *world) 50 | { 51 | for (size_t i = 0; i < 8; i++) 52 | { 53 | auto tS = node->get_child(std::to_string(i))->get_child(u"info")->get_child(u"tS"); 54 | 55 | if (tS != nullptr) 56 | { 57 | for (auto &[key, val] : node->get_child(std::to_string(i))->get_child(u"tile")->get_children()) 58 | { 59 | auto id = std::stoi(std::string{key.begin(), key.end()}); 60 | Tile *tile = new Tile(val[0], dynamic_cast *>(tS)->get(), i, id, world); 61 | world->add_entity(tile); 62 | } 63 | } 64 | } 65 | } 66 | 67 | void Map::load_background(wz::Node *node, World *world) 68 | { 69 | node = node->get_child(u"back"); 70 | if (node != nullptr) 71 | { 72 | for (auto &[key, val] : node->get_children()) 73 | { 74 | auto id = std::stoi(std::string{key.begin(), key.end()}); 75 | BackGround *bac = new BackGround(val[0], id, world); 76 | world->add_entity(bac); 77 | } 78 | } 79 | } 80 | 81 | void Map::load_string(int map_id, World *world) 82 | { 83 | auto node = world->get_resource().String->get_root()->find_from_path("Map.img"); 84 | for (auto &[key, val] : node->get_children()) 85 | { 86 | if (val[0]->get_child(std::to_string(map_id)) != nullptr) 87 | { 88 | 89 | printf(""); 90 | } 91 | } 92 | } 93 | 94 | void Map::load_foothold(wz::Node *node, World *world) 95 | { 96 | node = node->get_child(u"foothold"); 97 | if (node != nullptr) 98 | { 99 | for (auto &[page, val] : node->get_children()) 100 | { 101 | for (auto &[zmass, val] : val[0]->get_children()) 102 | { 103 | for (auto &[key, val] : val[0]->get_children()) 104 | { 105 | auto id = std::stoi(std::string{key.begin(), key.end()}); 106 | FootHold *f = new FootHold(val[0], std::stoi(std::string{page.begin(), page.end()}), std::stoi(std::string{zmass.begin(), zmass.end()}), world); 107 | f->set_id(id); 108 | world->add_entity(f, id); 109 | } 110 | } 111 | } 112 | } 113 | } 114 | 115 | void Map::load_life(wz::Node *node, World *world) 116 | { 117 | node = node->get_child(u"life"); 118 | if (node != nullptr) 119 | { 120 | for (auto &[key, val] : node->get_children()) 121 | { 122 | auto type = dynamic_cast *>(val[0]->get_child(u"type"))->get(); 123 | auto id = std::stoi(std::string{key.begin(), key.end()}); 124 | if (type == u"n") 125 | { 126 | auto rx0 = dynamic_cast *>(val[0]->get_child(u"rx0"))->get(); 127 | auto rx1 = dynamic_cast *>(val[0]->get_child(u"rx1"))->get(); 128 | auto npc = new Npc(val[0], id, rx0, rx1, world); 129 | world->add_entity(npc); 130 | } 131 | else if (type == u"m") 132 | { 133 | auto rx0 = dynamic_cast *>(val[0]->get_child(u"rx0"))->get(); 134 | auto rx1 = dynamic_cast *>(val[0]->get_child(u"rx1"))->get(); 135 | auto mob = new Mob(val[0], id, rx0, rx1, world); 136 | world->add_entity(mob); 137 | } 138 | } 139 | } 140 | } 141 | 142 | void Map::load_border(wz::Node *node, World *world) 143 | { 144 | auto border = new Border(node, world); 145 | world->add_entity(border); 146 | } 147 | 148 | void Map::load_ladderRope(wz::Node *node, World *world) 149 | { 150 | node = node->get_child(u"ladderRope"); 151 | if (node != nullptr) 152 | { 153 | for (auto it : node->get_children()) 154 | { 155 | auto id = std::stoi(std::string{it.first.begin(), it.first.end()}); 156 | auto lad = new LadderRope(it.second[0], world); 157 | lad->set_id(id); 158 | world->add_entity(lad, id); 159 | } 160 | } 161 | } 162 | 163 | void Map::load_portal(wz::Node *node, World *world) 164 | { 165 | node = node->get_child(u"portal"); 166 | if (node != nullptr) 167 | { 168 | for (auto &[key, val] : node->get_children()) 169 | { 170 | auto id = std::stoi(std::string{key.begin(), key.end()}); 171 | Portal *por = new Portal(val[0], world); 172 | por->set_id(id); 173 | world->add_entity(por, id); 174 | } 175 | } 176 | } 177 | 178 | void Map::load_bgm(wz::Node *node, World *world) 179 | { 180 | node = node->find_from_path("info/bgm"); 181 | if (node != nullptr) 182 | { 183 | auto url = dynamic_cast *>(node)->get(); 184 | url.insert(url.find('/'), u".img"); 185 | node = world->get_resource().Sound->get_root()->find_from_path(url); 186 | auto sou = Sound::load(node); 187 | world->add_unique_component(sou); 188 | } 189 | return; 190 | } 191 | 192 | void Map::clean_up(World *world) 193 | { 194 | world->clear_entity(); 195 | world->clear_entity(); 196 | world->clear_entity(); 197 | world->clear_entity(); 198 | world->clear_entity(); 199 | world->clear_entity(); 200 | world->clear_entity(); 201 | world->clear_entity(); 202 | world->clear_entity(); 203 | } 204 | 205 | wz::Node *Map::load_map_node(int map_id, World *world) 206 | { 207 | auto node = world->get_resource().Map->get_root(); 208 | auto s = std::to_string(map_id); 209 | if (s.size() < 9) 210 | { 211 | s.insert(0, 9 - s.size(), '0'); 212 | } 213 | std::string path = "Map/Map" + std::to_string(map_id / 100000000) + "/" + s + ".img"; 214 | return node->find_from_path(path); 215 | } 216 | 217 | uint32_t Map::get_map_id() 218 | { 219 | return map_id; 220 | } 221 | 222 | void Map::set_map_id(uint32_t id) 223 | { 224 | map_id = id; 225 | } -------------------------------------------------------------------------------- /sdlms/Core/Map.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "World.h" 3 | #include "wz/Property.hpp" 4 | #include "Components/Sound.h" 5 | 6 | // 用于加载地图中各种组件 7 | class Map 8 | { 9 | public: 10 | static void load(int map_id, World *world); 11 | static void load_obj(wz::Node *node, World *world); 12 | static void load_tile(wz::Node *node, World *world); 13 | static void load_background(wz::Node *node, World *world); 14 | static void load_string(int map_id, World *world); 15 | static void load_foothold(wz::Node *node, World *world); 16 | static void load_life(wz::Node *node, World *world); 17 | static void load_border(wz::Node *node, World *world); 18 | static void load_ladderRope(wz::Node *node, World *world); 19 | static void load_portal(wz::Node *node, World *world); 20 | 21 | static void load_bgm(wz::Node *node, World *world); 22 | static void clean_up(World *world); 23 | static uint32_t get_map_id(); 24 | 25 | private: 26 | static wz::Node *load_map_node(int map_id, World *world); 27 | static void set_map_id(uint32_t id); 28 | static inline uint32_t map_id = 0; 29 | }; -------------------------------------------------------------------------------- /sdlms/Core/MathHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //Math functions 5 | class MathHelper 6 | { 7 | public://模板函数 8 | template 9 | static T Random(T min, T max) 10 | { 11 | static std::random_device rd; 12 | static std::mt19937 gen(rd()); 13 | if constexpr (std::is_integral::value) { 14 | std::uniform_int_distribution dis(min, max); 15 | return dis(gen); 16 | } else { 17 | std::uniform_real_distribution dis(min, max); 18 | return dis(gen); 19 | } 20 | } 21 | 22 | 23 | static double Random() 24 | { 25 | return Random(0.f, 1.f); 26 | } 27 | 28 | template 29 | static T Clamp(T value, T min, T max) 30 | { 31 | if (value < min) 32 | return min; 33 | if (value > max) 34 | return max; 35 | return value; 36 | } 37 | 38 | 39 | template 40 | static T Lerp(T a, T b, float t) 41 | { 42 | return (1 - t) * a + t * b; 43 | } 44 | 45 | template 46 | static T SmoothStep(T a, T b, float t) 47 | { 48 | t = Clamp(t, 0.0f, 1.0f); 49 | t = t * t * (3 - 2 * t); 50 | return Lerp(a, b, t); 51 | } 52 | 53 | 54 | template 55 | static T SmoothDamp(T current, T target, T& currentVelocity, float smoothTime, float deltaTime) 56 | { 57 | float omega = 2.0f / smoothTime; 58 | float x = omega * deltaTime; 59 | float exp = 1.0f / (1.0f + x + 0.48f * x * x + 0.235f * x * x * x); 60 | float change = current - target; 61 | float originalTo = target; 62 | float temp = (currentVelocity + omega * change) * deltaTime; 63 | currentVelocity = (currentVelocity - omega * temp) * exp; 64 | float output = target + (change + temp) * exp; 65 | if (originalTo - current > 0.0f == output - target > 0.0f) 66 | { 67 | if (temp > 0.0f) 68 | output = originalTo; 69 | else 70 | output = current; 71 | currentVelocity = (output - originalTo) / deltaTime; 72 | } 73 | return output; 74 | } 75 | 76 | 77 | template 78 | static T MoveTowards(T current, T target, T maxDelta) 79 | { 80 | if (Abs(target - current) <= maxDelta) 81 | return target; 82 | return current + Sign(target - current) * maxDelta; 83 | } 84 | 85 | template 86 | static T Sign(T value) 87 | { 88 | if (value > 0) 89 | return 1; 90 | if (value < 0) 91 | return -1; 92 | return 0; 93 | } 94 | 95 | template 96 | static T Abs(T value) 97 | { 98 | if (value < 0) 99 | return -value; 100 | return value; 101 | } 102 | 103 | template 104 | static T Max(T a, T b) 105 | { 106 | if (a > b) 107 | return a; 108 | return b; 109 | } 110 | 111 | template 112 | static T Min(T a, T b) 113 | { 114 | if (a < b) 115 | return a; 116 | return b; 117 | } 118 | 119 | template 120 | static T Clamp01(T value) 121 | { 122 | return Clamp(value, 0, 1); 123 | } 124 | 125 | }; 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /sdlms/Core/Window.cpp: -------------------------------------------------------------------------------- 1 | #include "Window.h" 2 | 3 | #include 4 | 5 | #include "Core/ECSSystem.h" 6 | 7 | #include 8 | 9 | void Window::create_window(const char *title, unsigned int width, unsigned int height, unsigned int pixel_scale_h, unsigned int pixel_scale_v) 10 | { 11 | int result = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO); 12 | [[unlikely]] 13 | if (result < 0) 14 | { 15 | ECS_PRINT_ERROR("Failed to initialize SDL (%s)", SDL_GetError()); 16 | std::abort(); 17 | } 18 | window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN); 19 | [[unlikely]] 20 | if (!window) 21 | { 22 | ECS_PRINT_ERROR("Failed to create SDL window (%s)", SDL_GetError()); 23 | std::abort(); 24 | } 25 | renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 26 | 27 | SDL_RenderSetLogicalSize(renderer, width, height); 28 | 29 | window_title = title; 30 | } 31 | 32 | void Window::destroy_window() 33 | { 34 | SDL_DestroyRenderer(renderer); 35 | SDL_DestroyWindow(window); 36 | } 37 | 38 | SDL_Window *Window::get_main_window() 39 | { 40 | return window; 41 | } 42 | 43 | SDL_Renderer *Window::get_renderer() 44 | { 45 | return renderer; 46 | } 47 | 48 | const char *Window::get_title() 49 | { 50 | return window_title; 51 | } 52 | 53 | SDL_Point Window::get_mouse_position() 54 | { 55 | return {mouse_x, mouse_y}; 56 | } 57 | 58 | void Window::clear() 59 | { 60 | SDL_RenderClear(renderer); 61 | } 62 | 63 | void Window::update() 64 | { 65 | SDL_GetMouseState(&mouse_x, &mouse_y); 66 | SDL_RenderPresent(renderer); 67 | } 68 | -------------------------------------------------------------------------------- /sdlms/Core/Window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | class Window { 8 | private: 9 | static inline SDL_Window* window; 10 | static inline SDL_Renderer* renderer; 11 | 12 | static inline int mouse_x; 13 | static inline int mouse_y; 14 | 15 | static inline const char* window_title; 16 | 17 | public: 18 | static void create_window(const char* title, unsigned int width, unsigned int height, unsigned int pixel_scale_h = 1, unsigned int pixel_scale_v = 1); 19 | static void destroy_window(); 20 | 21 | static SDL_Window* get_main_window(); 22 | static SDL_Renderer* get_renderer(); 23 | 24 | static const char* get_title(); 25 | 26 | static SDL_Point get_mouse_position(); 27 | 28 | static void clear(); 29 | static void update(); 30 | }; 31 | -------------------------------------------------------------------------------- /sdlms/Core/World.cpp: -------------------------------------------------------------------------------- 1 | #include "World.h" 2 | #include "Input.h" 3 | #include "ECSSystem.h" 4 | 5 | #include 6 | 7 | SDL_FPoint operator+(const SDL_FPoint &m, const SDL_FPoint &n) 8 | { 9 | return {m.x + n.x, m.y + n.y}; 10 | } 11 | 12 | // 重载 SDL_Point 的减法运算符 13 | SDL_FPoint operator-(const SDL_FPoint &m, const SDL_FPoint &n) 14 | { 15 | return {m.x - n.x, m.y - n.y}; 16 | } 17 | 18 | World::World() : dt_now{SDL_GetTicks()}, dt_last{0}, delta_time{0}, quit{false} 19 | { 20 | world = this; 21 | } 22 | World::~World() {} 23 | 24 | void World::add_entity(Entity *ent) 25 | { 26 | auto index = entity_map[typeid(*ent)].size(); 27 | add_entity(ent, index); 28 | } 29 | 30 | void World::add_entity(Entity *ent, int index) 31 | { 32 | entity_map[typeid(*ent)].emplace(index, ent); 33 | ent->set_id(index); 34 | } 35 | 36 | void World::add_component(Component *comp) 37 | { 38 | auto index = component_map[typeid(*comp)].size(); 39 | add_component(comp, index); 40 | } 41 | 42 | void World::add_component(Component *comp, int index) 43 | { 44 | component_map[typeid(*comp)].emplace(index, comp); 45 | comp->set_id(index); 46 | } 47 | 48 | void World::add_unique_component(Component *comp) 49 | { 50 | for (const auto &[key, value] : component_map[typeid(*comp)]) 51 | { 52 | [[unlikely]] 53 | if (value == comp) 54 | { 55 | // 避免重复添加到world 56 | return; 57 | } 58 | } 59 | add_component(comp); 60 | } 61 | 62 | void World::add_system(System *sys) 63 | { 64 | system_list.push_back(sys); 65 | 66 | DEBUG_PRINT("Added a new system (%s)", typeid(*sys).name()); 67 | } 68 | 69 | void World::add_resource(Resource *r) 70 | { 71 | resource_map[typeid(*r)] = r; 72 | 73 | DEBUG_PRINT("Added a new system (%s)", typeid(*sys).name()); 74 | } 75 | 76 | void World::destroy_entity(Entity *ent, bool destroy_components) 77 | { 78 | if (destroy_components) 79 | { 80 | for (auto &[key, val] : ent->get_components()) 81 | { 82 | [[likely]] 83 | if (val != nullptr) 84 | { 85 | destroy_component(val, true); 86 | } 87 | } 88 | } 89 | auto &target_map = entity_map[typeid(*ent)]; 90 | for (auto it = target_map.begin(); it != target_map.end();) 91 | { 92 | [[unlikely]] 93 | if (it->second == ent) 94 | { 95 | it = target_map.erase(it); // 删除匹配值的元素,并返回指向下一个元素的迭代器 96 | } 97 | else 98 | { 99 | ++it; 100 | } 101 | } 102 | if (target_map.size() == 0) 103 | { 104 | entity_map.erase(typeid(*ent)); 105 | } 106 | delete ent; 107 | } 108 | 109 | void World::remove_entity(Entity *ent) 110 | { 111 | auto &target_map = entity_map[typeid(*ent)]; 112 | for (auto it = target_map.begin(); it != target_map.end();) 113 | { 114 | [[unlikely]] 115 | if (it->second == ent) 116 | { 117 | it = target_map.erase(it); // 删除匹配值的元素,并返回指向下一个元素的迭代器 118 | } 119 | else 120 | { 121 | ++it; 122 | } 123 | } 124 | } 125 | 126 | void World::destroy_component(Component *comp, bool delete_component) 127 | { 128 | if (comp != nullptr) 129 | { 130 | auto &target_map = component_map[typeid(*comp)]; 131 | 132 | for (auto it = target_map.equal_range(comp->get_id()).first; it != target_map.equal_range(comp->get_id()).second;) 133 | { 134 | if (it->second == comp) 135 | { 136 | it = target_map.erase(it); 137 | } 138 | else 139 | { 140 | ++it; 141 | } 142 | } 143 | if (target_map.size() == 0) 144 | { 145 | component_map.erase(typeid(*comp)); 146 | } 147 | if (delete_component) 148 | { 149 | delete comp; 150 | } 151 | } 152 | } 153 | 154 | void World::poll_events() 155 | { 156 | Input::update_momentary_keys(); 157 | 158 | while (SDL_PollEvent(&event_handler) != 0) 159 | { 160 | switch (event_handler.type) 161 | { 162 | case SDL_EventType::SDL_QUIT: 163 | { 164 | quit = true; 165 | } 166 | break; 167 | 168 | case SDL_EventType::SDL_KEYDOWN: 169 | { 170 | Input::process_input_event(Input::EventType::KeyPressed, event_handler); 171 | } 172 | break; 173 | 174 | case SDL_EventType::SDL_KEYUP: 175 | { 176 | Input::process_input_event(Input::EventType::KeyReleased, event_handler); 177 | } 178 | break; 179 | 180 | case SDL_EventType::SDL_MOUSEBUTTONDOWN: 181 | { 182 | Input::process_input_event(Input::EventType::MousePressed, event_handler); 183 | } 184 | break; 185 | 186 | case SDL_EventType::SDL_MOUSEBUTTONUP: 187 | { 188 | Input::process_input_event(Input::EventType::MouseReleased, event_handler); 189 | } 190 | break; 191 | } 192 | } 193 | } 194 | 195 | void World::tick_delta_time() 196 | { 197 | dt_last = dt_now; 198 | dt_now = SDL_GetTicks(); 199 | delta_time = dt_now - dt_last; 200 | } 201 | 202 | void World::process_systems() 203 | { 204 | for (System *sys : system_list) 205 | { 206 | if (sys) 207 | sys->run(*this); 208 | } 209 | } 210 | 211 | int World::get_delta_time() const 212 | { 213 | return delta_time; 214 | } 215 | 216 | void World::set_delta_time(int value) 217 | { 218 | delta_time = value; 219 | } 220 | 221 | Window *World::get_window() const 222 | { 223 | return window; 224 | } 225 | 226 | void World::set_window(Window *value) 227 | { 228 | window = value; 229 | } 230 | 231 | bool World::is_game_quit() const 232 | { 233 | return quit; 234 | } 235 | 236 | void World::clean_up() 237 | { 238 | #ifdef ECS_DEBUG 239 | size_t ccount = 0; 240 | for (auto &pair : component_map) 241 | ccount += pair.second.size(); 242 | 243 | ECS_PRINT("DESTROYING EVERYTHING (%lu entities and %lu components)", entity_list.size(), ccount); 244 | #endif 245 | 246 | for (auto &pair : component_map) 247 | { 248 | for (auto &[index, comp] : pair.second) 249 | { 250 | destroy_component(comp, true); 251 | } 252 | } 253 | 254 | for (auto &[key, val] : entity_map) 255 | { 256 | for (auto &[id, ent] : val) 257 | { 258 | destroy_entity(ent, true); 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /sdlms/Core/World.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entities/Entity.h" 4 | #include "Components/Component.h" 5 | #include "Systems/System.h" 6 | #include "Resource/Resource.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "Core/Window.h" 16 | #include 17 | #include 18 | 19 | // 重载 SDL_Point 的加法运算符 20 | SDL_FPoint operator+(const SDL_FPoint &m, const SDL_FPoint &n); 21 | // 重载 SDL_Point 的减法运算符 22 | SDL_FPoint operator-(const SDL_FPoint &m, const SDL_FPoint &n); 23 | 24 | class World 25 | { 26 | private: 27 | static unsigned long EntityCounter; 28 | 29 | struct ComponentStore 30 | { 31 | std::type_index type; 32 | Component *component; 33 | }; 34 | 35 | std::unordered_map> entity_map; 36 | std::unordered_map> component_map; 37 | std::vector system_list; 38 | 39 | SDL_Event event_handler; 40 | 41 | std::uint64_t dt_now; 42 | std::uint64_t dt_last; 43 | int delta_time; 44 | 45 | Window *window; 46 | 47 | bool quit; 48 | 49 | std::unordered_map resource_map; 50 | 51 | static inline World *world = nullptr; 52 | 53 | public: 54 | World(); 55 | ~World(); 56 | 57 | static World *get_world() 58 | { 59 | return world; 60 | }; 61 | 62 | void add_entity(Entity *ent); 63 | void add_entity(Entity *ent, int index); 64 | 65 | void add_component(Component *comp); 66 | void add_component(Component *comp, int index); 67 | void add_unique_component(Component *comp); 68 | 69 | void add_system(System *system); 70 | 71 | void add_resource(Resource *r); 72 | 73 | void destroy_entity(Entity *ent, bool destroy_components = true); 74 | 75 | template 76 | void clear_entity() 77 | { 78 | auto &target_map = *reinterpret_cast *>(&entity_map[typeid(C)]); 79 | for (auto &[key, val] : target_map) 80 | { 81 | delete val; 82 | } 83 | target_map.clear(); 84 | entity_map.erase(typeid(C)); 85 | }; 86 | 87 | void remove_entity(Entity *ent); 88 | 89 | void destroy_component(Component *comp, bool delete_component = true); 90 | 91 | inline const auto &get_entity_map() const { return entity_map; } 92 | inline const auto &get_component_map() const { return component_map; } 93 | inline const auto &get_system_list() const { return system_list; } 94 | 95 | template 96 | bool components_exist_of_type() 97 | { 98 | return component_map.contains(typeid(C)); 99 | } 100 | 101 | template 102 | std::multimap &get_components() 103 | { 104 | return *reinterpret_cast *>(&component_map[typeid(C)]); 105 | } 106 | 107 | template 108 | bool entity_exist_of_type() 109 | { 110 | return entity_map.contains(typeid(C)); 111 | } 112 | 113 | template 114 | std::multimap &get_entitys() 115 | { 116 | return *reinterpret_cast *>(&entity_map[typeid(C)]); 117 | } 118 | 119 | template 120 | C &get_resource() 121 | { 122 | return *reinterpret_cast(resource_map.at(typeid(C))); 123 | } 124 | 125 | void initialize_entities(); 126 | void poll_events(); 127 | void tick_delta_time(); 128 | 129 | void process_systems(); 130 | 131 | int get_delta_time() const; 132 | void set_delta_time(int value); 133 | 134 | Window *get_window() const; 135 | void set_window(Window *value); 136 | 137 | bool is_game_quit() const; 138 | 139 | void clean_up(); 140 | }; 141 | -------------------------------------------------------------------------------- /sdlms/Entities/BackGround.cpp: -------------------------------------------------------------------------------- 1 | #include "BackGround.h" 2 | #include "Resource/Wz.h" 3 | #include "Components/Sprite.h" 4 | #include "Components/AnimatedSprite.h" 5 | #include "Components/HVTile.h" 6 | #include "Components/HVMove.h" 7 | #include "Components/Transform.h" 8 | 9 | BackGround::BackGround(wz::Node *node, int id, World *world) 10 | { 11 | auto bS = dynamic_cast *>(node->get_child(u"bS"))->get(); 12 | if (bS == u"") 13 | { 14 | return; 15 | } 16 | 17 | auto ani = 0; 18 | if (node->get_child(u"ani") != nullptr) 19 | { 20 | ani = dynamic_cast *>(node->get_child(u"ani"))->get(); 21 | } 22 | 23 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 24 | auto y = dynamic_cast *>(node->get_child(u"y"))->get(); 25 | 26 | auto cx = dynamic_cast *>(node->get_child(u"cx"))->get(); 27 | auto cy = dynamic_cast *>(node->get_child(u"cy"))->get(); 28 | 29 | auto rx = dynamic_cast *>(node->get_child(u"rx"))->get(); 30 | auto ry = dynamic_cast *>(node->get_child(u"ry"))->get(); 31 | 32 | auto type = dynamic_cast *>(node->get_child(u"type"))->get(); 33 | 34 | auto no = dynamic_cast *>(node->get_child(u"no"))->get(); 35 | 36 | auto front = 0; 37 | if (node->get_child(u"front") != nullptr) 38 | { 39 | front = dynamic_cast *>(node->get_child(u"front"))->get(); 40 | } 41 | 42 | auto flip = 0; 43 | if (node->get_child(u"f") != nullptr) 44 | { 45 | flip = dynamic_cast *>(node->get_child(u"f"))->get(); 46 | } 47 | 48 | auto a = 255; 49 | if (node->get_child(u"a") != nullptr) 50 | { 51 | a = dynamic_cast *>(node->get_child(u"a"))->get(); 52 | } 53 | 54 | auto no_str = std::to_string(no); 55 | 56 | HVTile *hvt = nullptr; 57 | HVMove *hvm = nullptr; 58 | 59 | Transform *t = new Transform((float)x, (float)y, flip); 60 | add_component(t); 61 | 62 | switch (type) 63 | { 64 | case NORMAL: 65 | hvt = new HVTile(cx, cy, false, false); 66 | break; 67 | case HTILED: 68 | case HMOVEA: 69 | hvt = new HVTile(cx, cy, true, false); 70 | break; 71 | case VTILED: 72 | case VMOVEA: 73 | hvt = new HVTile(cx, cy, false, true); 74 | break; 75 | case TILED: 76 | case HMOVEB: 77 | case VMOVEB: 78 | hvt = new HVTile(cx, cy, true, true); 79 | break; 80 | } 81 | switch (type) 82 | { 83 | case HMOVEA: 84 | case HMOVEB: 85 | hvm = new HVMove(rx, ry, true, false); 86 | break; 87 | case VMOVEA: 88 | case VMOVEB: 89 | hvm = new HVMove(rx, ry, false, true); 90 | break; 91 | default: 92 | hvm = new HVMove(rx, ry, false, false); 93 | break; 94 | } 95 | add_component(hvt); 96 | add_component(hvm); 97 | 98 | if (front == 1) 99 | { 100 | id = 99999999 + id; 101 | } 102 | 103 | switch (ani) 104 | { 105 | case 0: 106 | { 107 | auto url = u"Back/" + bS + u".img/" + u"back" + u"/" + std::u16string{no_str.begin(), no_str.end()}; 108 | Sprite *spr = new Sprite(world->get_resource().Map->get_root()->find_from_path(url), a); 109 | add_component(spr); 110 | world->add_component(t, id - 1000); 111 | break; 112 | } 113 | case 1: 114 | { 115 | auto url = u"Back/" + bS + u".img/" + u"ani" + u"/" + std::u16string{no_str.begin(), no_str.end()}; 116 | AnimatedSprite *aspr = new AnimatedSprite(world->get_resource().Map->get_root()->find_from_path(url), a); 117 | add_component(aspr); 118 | world->add_component(t, id - 1000); 119 | world->add_component(aspr); 120 | break; 121 | } 122 | default: 123 | break; 124 | } 125 | } 126 | 127 | BackGround::~BackGround() 128 | { 129 | auto world = World::get_world(); 130 | if (get_component() != nullptr) 131 | { 132 | auto spr = get_component(); 133 | delete spr; 134 | } 135 | else 136 | { 137 | auto aspr = get_component(); 138 | world->destroy_component(aspr, false); 139 | delete aspr; 140 | } 141 | 142 | auto hvt = get_component(); 143 | delete hvt; 144 | 145 | auto hvm = get_component(); 146 | delete hvm; 147 | 148 | auto t = get_component(); 149 | world->destroy_component(t, false); 150 | delete t; 151 | } 152 | -------------------------------------------------------------------------------- /sdlms/Entities/BackGround.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Entity.h" 3 | #include "wz/Property.hpp" 4 | #include "Core/World.h" 5 | 6 | class BackGround : public Entity 7 | { 8 | public: 9 | BackGround(wz::Node *node, int id, World *world); 10 | ~BackGround(); 11 | 12 | enum 13 | { 14 | NORMAL, 15 | HTILED, 16 | VTILED, 17 | TILED, 18 | HMOVEA, 19 | VMOVEA, 20 | HMOVEB, 21 | VMOVEB 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /sdlms/Entities/Border.cpp: -------------------------------------------------------------------------------- 1 | #include "Border.h" 2 | #include "FootHold.h" 3 | #include "Components/Line.h" 4 | 5 | Border::Border(wz::Node *node, World *world) 6 | { 7 | if (node->find_from_path(u"info/VRLeft") != nullptr) 8 | { 9 | // 优先从mapinfo获取边界 10 | node = node->find_from_path(u"info"); 11 | left = dynamic_cast *>(node->get_child(u"VRLeft"))->get(); 12 | right = dynamic_cast *>(node->get_child(u"VRRight"))->get(); 13 | top = dynamic_cast *>(node->get_child(u"VRTop"))->get(); 14 | bottom = dynamic_cast *>(node->get_child(u"VRBottom"))->get(); 15 | } 16 | else 17 | { 18 | if (world->entity_exist_of_type()) 19 | { 20 | // 从fh计算出来 21 | for (auto &[id, fh] : world->get_entitys()) 22 | { 23 | auto rl = fh->get_component(); 24 | auto x1 = rl->get_m().x; 25 | auto y1 = rl->get_m().y; 26 | auto x2 = rl->get_n().x; 27 | auto y2 = rl->get_n().y; 28 | if (!left.has_value()) 29 | { 30 | left = std::min({x1, x2}); 31 | } 32 | left = std::min({left.value(), x1, x2}); 33 | if (!right.has_value()) 34 | { 35 | right = std::max({x1, x2}); 36 | } 37 | right = std::max({right.value(), x1, x2}); 38 | if (!top.has_value()) 39 | { 40 | top = std::min({y1, y2}); 41 | } 42 | top = std::min({top.value(), y1, y2}); 43 | if (!bottom.has_value()) 44 | { 45 | bottom = std::max({y1, y2}); 46 | } 47 | bottom = std::max({bottom.value(), y1, y2}); 48 | } 49 | left = left.value() + 25; 50 | right = right.value() - 25; 51 | top = top.value() - 300; 52 | bottom = bottom.value() + 100; 53 | } 54 | } 55 | } 56 | 57 | Border::~Border() 58 | { 59 | } 60 | -------------------------------------------------------------------------------- /sdlms/Entities/Border.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Entity.h" 3 | #include "wz/Property.hpp" 4 | #include 5 | 6 | class Border : public Entity 7 | { 8 | public: 9 | Border(wz::Node *node, World *world); 10 | ~Border(); 11 | constexpr auto get_left() { return left; } 12 | constexpr auto get_right() { return right; } 13 | constexpr auto get_top() { return top; } 14 | constexpr auto get_bottom() { return bottom; } 15 | 16 | private: 17 | std::optional left = std::nullopt; 18 | std::optional right = std::nullopt; 19 | std::optional top = std::nullopt; 20 | std::optional bottom = std::nullopt; 21 | }; 22 | -------------------------------------------------------------------------------- /sdlms/Entities/Character.cpp: -------------------------------------------------------------------------------- 1 | #include "Character.h" 2 | #include "NameTag.h" 3 | #include "String.h" 4 | #include "ChatBalloon.h" 5 | 6 | #include "Components/Avatar.h" 7 | #include "Components/Transform.h" 8 | #include "Components/LimitTransform.h" 9 | #include "Components/RelativeTransform.h" 10 | #include "Resource/Wz.h" 11 | 12 | #include 13 | 14 | Character::Character(World *world, SDL_FPoint p) 15 | { 16 | auto ava = Avatar::load(); 17 | ava->add_head(u"00012006"); 18 | ava->add_body(u"00002006"); 19 | ava->add_coat(u"01040036"); 20 | ava->add_pants(u"01060026"); 21 | ava->add_face(u"00020000"); 22 | ava->add_hairs(u"00030000"); 23 | ava->add_cap(u"01000016"); 24 | ava->add_shoes(u"01070002"); 25 | ava->add_weapon(u"01302009"); 26 | ava->add_shield(u"01092030"); 27 | 28 | add_component(ava); 29 | world->add_component(ava); 30 | 31 | Transform *tr = new Transform(p); 32 | add_component(tr); 33 | world->add_component(tr, 3000000); 34 | 35 | // 限制人物移动范围 36 | LimitTransform *ltr = new LimitTransform(tr, std::nullopt, std::nullopt); 37 | add_component(ltr); 38 | world->add_component(ltr); 39 | 40 | auto str = new String(u"逆向萌新"); 41 | add_entity(str); 42 | auto spr = str->get_component(); 43 | 44 | auto nam = new NameTag(spr->width, spr->height, u"13"); 45 | add_entity(nam); 46 | auto rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-nam->get_width() / 2), (float)6}); 47 | nam->add_component(rtr); 48 | nam->add_component(new Transform()); 49 | world->add_component(rtr, 0); 50 | 51 | rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-spr->get_width() / 2), (float)6 + (nam->get_height() - spr->height) / 2}); 52 | str->add_component(rtr); 53 | str->add_component(new Transform()); 54 | world->add_component(rtr, 0); 55 | 56 | } 57 | 58 | void Character::switch_act(uint8_t action) 59 | { 60 | auto ava = get_component(); 61 | if (action != ava->act) 62 | { 63 | ava->act_index = 0; 64 | ava->act_time = 0; 65 | ava->act = action; 66 | } 67 | } 68 | 69 | void Character::stop_animate() 70 | { 71 | get_component()->animate = false; 72 | } 73 | 74 | void Character::start_animate() 75 | { 76 | get_component()->animate = true; 77 | } 78 | 79 | Character::~Character() 80 | { 81 | auto world = World::get_world(); 82 | auto ava = get_component(); 83 | world->destroy_component(ava, false); 84 | delete ava; 85 | } -------------------------------------------------------------------------------- /sdlms/Entities/Character.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Entity.h" 3 | #include "Core/World.h" 4 | 5 | class Character : public Entity 6 | { 7 | public: 8 | Character(World *world, SDL_FPoint p); 9 | ~Character(); 10 | 11 | void switch_act(uint8_t action); 12 | void stop_animate(); 13 | void start_animate(); 14 | }; 15 | -------------------------------------------------------------------------------- /sdlms/Entities/ChatBalloon.cpp: -------------------------------------------------------------------------------- 1 | #include "ChatBalloon.h" 2 | #include "Resource/Wz.h" 3 | 4 | ChatBalloon::ChatBalloon(int width, int height, const std::u16string &val) 5 | { 6 | spr = new Sprite(World::get_world()->get_resource().UI->get_root()->find_from_path(u"ChatBalloon.img/" + val), 7 | width, height, Sprite::ChatBallon); 8 | add_component(spr); 9 | } 10 | 11 | int ChatBalloon::get_width() 12 | { 13 | return get_component()->get_width(); 14 | } 15 | 16 | int ChatBalloon::get_height() 17 | { 18 | return get_component()->get_height(); 19 | } 20 | 21 | ChatBalloon::~ChatBalloon() 22 | { 23 | delete spr; 24 | } 25 | -------------------------------------------------------------------------------- /sdlms/Entities/ChatBalloon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | #include "Components/Sprite.h" 7 | 8 | class ChatBalloon : public Entity 9 | { 10 | public: 11 | ChatBalloon(int width, int height, const std::u16string &val); 12 | ~ChatBalloon(); 13 | int get_width(); 14 | int get_height(); 15 | 16 | public: 17 | Sprite *spr; 18 | }; 19 | -------------------------------------------------------------------------------- /sdlms/Entities/Entity.cpp: -------------------------------------------------------------------------------- 1 | #include "Entity.h" 2 | 3 | Entity::Entity() {} 4 | Entity::~Entity() {} 5 | 6 | 7 | -------------------------------------------------------------------------------- /sdlms/Entities/Entity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class Component; 8 | 9 | class Entity 10 | { 11 | private: 12 | int id = 0; 13 | std::unordered_map component_refs; 14 | std::unordered_map> entity_refs; 15 | 16 | public: 17 | Entity(); 18 | virtual ~Entity(); 19 | 20 | int get_id() 21 | { 22 | return id; 23 | }; 24 | void set_id(int value) 25 | { 26 | id = value; 27 | }; 28 | 29 | template 30 | void add_component(C *comp) 31 | { 32 | remove_component(); 33 | component_refs[typeid(C)] = comp; 34 | if (comp != nullptr) 35 | { 36 | comp->set_owner(this); 37 | } 38 | } 39 | 40 | template 41 | void remove_component() 42 | { 43 | if (component_refs.contains(typeid(C))) 44 | { 45 | C *comp = static_cast(component_refs[typeid(C)]); 46 | comp->set_owner(nullptr); 47 | } 48 | component_refs.erase(typeid(C)); 49 | } 50 | 51 | template 52 | C *get_component(); 53 | 54 | int add_entity(Entity *ent) 55 | { 56 | auto index = entity_refs[typeid(*ent)].size(); 57 | add_entity(ent, index); 58 | return index; 59 | }; 60 | 61 | void add_entity(Entity *ent, int index) 62 | { 63 | entity_refs[typeid(*ent)][index] = ent; 64 | }; 65 | 66 | template 67 | void remove_entity(int index) 68 | { 69 | entity_refs[typeid(C)].erase(index); 70 | } 71 | 72 | void remove_entity(Entity *ent) 73 | { 74 | auto &target_map = entity_refs[typeid(*ent)]; 75 | for (auto it = target_map.begin(); it != target_map.end();) 76 | { 77 | [[unlikely]] 78 | if (it->second == ent) 79 | { 80 | it = target_map.erase(it); // 删除匹配值的元素,并返回指向下一个元素的迭代器 81 | } 82 | else 83 | { 84 | ++it; 85 | } 86 | } 87 | }; 88 | 89 | template 90 | C *get_entity(int index) 91 | { 92 | if (entity_refs.contains(typeid(C)) && entity_refs[typeid(C)].contains(index)) 93 | { 94 | return static_cast(entity_refs[typeid(C)][index]); 95 | } 96 | else 97 | { 98 | return nullptr; 99 | } 100 | } 101 | 102 | template 103 | std::unordered_map &get_entity() 104 | { 105 | return *reinterpret_cast *>(&entity_refs[typeid(C)]); 106 | } 107 | 108 | const std::unordered_map &get_components() 109 | { 110 | return component_refs; 111 | }; 112 | }; 113 | 114 | #include "Components/Component.h" 115 | 116 | template 117 | C *Entity::get_component() 118 | { 119 | if (component_refs.contains(typeid(C))) 120 | { 121 | return static_cast(component_refs[typeid(C)]); 122 | } 123 | else 124 | { 125 | return nullptr; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /sdlms/Entities/FootHold.cpp: -------------------------------------------------------------------------------- 1 | #include "FootHold.h" 2 | #include "Components/Line.h" 3 | #include "Components/Physic/Normal.h" 4 | #include "Timer.h" 5 | 6 | FootHold::FootHold(wz::Node *node, int page, int zmass, World *world) : page(page), zmass(zmass) 7 | { 8 | next = dynamic_cast *>(node->get_child(u"next"))->get(); 9 | prev = dynamic_cast *>(node->get_child(u"prev"))->get(); 10 | auto x1 = dynamic_cast *>(node->get_child(u"x1"))->get(); 11 | auto x2 = dynamic_cast *>(node->get_child(u"x2"))->get(); 12 | auto y1 = dynamic_cast *>(node->get_child(u"y1"))->get(); 13 | auto y2 = dynamic_cast *>(node->get_child(u"y2"))->get(); 14 | 15 | Line *r = new Line({(float)x1, (float)y1}, {(float)x2, (float)y2}); 16 | add_component(r); 17 | } 18 | 19 | FootHold::~FootHold() 20 | { 21 | auto world = World::get_world(); 22 | 23 | auto r = get_component(); 24 | delete r; 25 | 26 | for (auto &[key, val] : get_entity()) 27 | { 28 | world->remove_entity(val); 29 | delete val; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sdlms/Entities/FootHold.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Entity.h" 3 | #include "wz/Property.hpp" 4 | #include "Core/World.h" 5 | 6 | class FootHold : public Entity 7 | { 8 | public: 9 | FootHold(wz::Node *node,int page, int zmass, World *world); 10 | ~FootHold(); 11 | 12 | public: 13 | constexpr auto get_page() { return page; } 14 | 15 | public: 16 | // fh的附加属性 17 | int page; 18 | int zmass; 19 | int prev; 20 | int next; 21 | }; 22 | -------------------------------------------------------------------------------- /sdlms/Entities/LadderRope.cpp: -------------------------------------------------------------------------------- 1 | #include "LadderRope.h" 2 | #include "Components/Line.h" 3 | #include "Components/Physic/Normal.h" 4 | 5 | LadderRope::LadderRope(wz::Node *node, World *world) 6 | { 7 | l = dynamic_cast *>(node->get_child(u"l"))->get(); 8 | uf = dynamic_cast *>(node->get_child(u"uf"))->get(); 9 | page = dynamic_cast *>(node->get_child(u"page"))->get(); 10 | 11 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 12 | auto y1 = dynamic_cast *>(node->get_child(u"y1"))->get(); 13 | auto y2 = dynamic_cast *>(node->get_child(u"y2"))->get(); 14 | 15 | auto *c = new Line{{(float)x, (float)y1}, {(float)x, (float)y2}}; 16 | add_component(c); 17 | } 18 | 19 | LadderRope::~LadderRope() 20 | { 21 | auto c = get_component(); 22 | delete c; 23 | } 24 | -------------------------------------------------------------------------------- /sdlms/Entities/LadderRope.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Entity.h" 3 | #include "wz/Property.hpp" 4 | #include "Core/World.h" 5 | 6 | class LadderRope : public Entity 7 | { 8 | public: 9 | LadderRope(wz::Node *node, World *world); 10 | ~LadderRope(); 11 | 12 | public: 13 | // lr的附加属性 14 | int l; 15 | int uf; 16 | int page; 17 | }; -------------------------------------------------------------------------------- /sdlms/Entities/Mob.cpp: -------------------------------------------------------------------------------- 1 | #include "Mob.h" 2 | 3 | #include "FootHold.h" 4 | #include "NameTag.h" 5 | #include "String.h" 6 | 7 | #include "Components/Sprite.h" 8 | #include "Components/Transform.h" 9 | #include "Components/RelativeTransform.h" 10 | #include "Components/RandomInput.h" 11 | #include "Components/LimitTransform.h" 12 | #include "Components/Line.h" 13 | #include "Components/Physic/Normal.h" 14 | #include "Resource/Wz.h" 15 | 16 | Mob::Mob(wz::Node *node, int id, int rx0, int rx1, World *world) 17 | { 18 | if (node != nullptr) 19 | { 20 | auto mob_id = dynamic_cast *>(node->get_child(u"id"))->get(); 21 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 22 | auto fh = dynamic_cast *>(node->get_child(u"fh"))->get(); 23 | auto foo = world->get_entitys().find(fh)->second; 24 | // 从fh获取y,layer 25 | auto y = foo->get_component()->get_y(x).value(); 26 | auto layer = foo->get_page(); 27 | 28 | node = world->get_resource().Mob->get_root()->find_from_path(mob_id + u".img"); 29 | // 排除 link 30 | while (node->find_from_path(u"info/link") != nullptr) 31 | { 32 | auto link = dynamic_cast *>(node->find_from_path(u"info/link"))->get(); 33 | node = world->get_resource().Mob->get_root()->find_from_path(link + u".img"); 34 | } 35 | 36 | Transform *tr = new Transform((float)x, (float)y); 37 | add_component(tr); 38 | world->add_component(tr, layer * 300000 + id + 30000); 39 | 40 | // 添加物理组件 41 | Normal *nor = new Normal(); 42 | nor->type = Normal::Ground; 43 | add_entity(foo, 0); 44 | add_component(nor); 45 | world->add_component(nor); 46 | 47 | // 添加自动移动组件 48 | RandomInput *ran = new RandomInput(); 49 | add_component(ran); 50 | world->add_component(ran); 51 | 52 | // 添加移动范围 53 | LimitTransform *ltr = new LimitTransform(tr, SDL_FPoint{(float)rx0, (float)rx1}, std::nullopt); 54 | add_component(ltr); 55 | world->add_component(ltr); 56 | 57 | for (auto &[name, val] : node->get_children()) 58 | { 59 | if (name == u"info") 60 | { 61 | // 获取mob基础属性 62 | auto speed = 0; 63 | if (val[0]->get_child(u"speed") != nullptr) 64 | { 65 | speed = dynamic_cast *>(val[0]->get_child(u"speed"))->get(); 66 | } 67 | nor->hspeed_limit = {-1 * (float)(speed + 100) / 100 * 125, (float)(speed + 100) / 100 * 125}; 68 | } 69 | else 70 | { 71 | auto aspr = new AnimatedSprite(val[0]); 72 | aspr_map[name] = aspr; 73 | world->add_component(aspr); 74 | } 75 | } 76 | if (aspr_map.size() > 0) 77 | { 78 | // 默认显示mob第一个状态 79 | auto aspr = aspr_map.begin()->second; 80 | add_component(aspr); 81 | } 82 | 83 | // 从string.wz获取信息 84 | node = world->get_resource().String->get_root()->find_from_path(u"Mob.img/" + mob_id.substr(mob_id.find_first_not_of(u'0'))); 85 | if (node != nullptr) 86 | { 87 | auto name = dynamic_cast *>(node->get_child(u"name"))->get(); 88 | auto str = new String(name, {255, 255, 255, 255}, 0, 12); 89 | add_entity(str); 90 | auto spr = str->get_component(); 91 | 92 | auto nam = new NameTag(spr->width, spr->height); 93 | add_entity(nam); 94 | auto rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-nam->get_width() / 2), 6}); 95 | nam->add_component(rtr); 96 | nam->add_component(new Transform()); 97 | world->add_component(rtr, 0); 98 | 99 | rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-spr->get_width() / 2), (float)6 + (nam->get_height() - spr->height) / 2}); 100 | str->add_component(rtr); 101 | str->add_component(new Transform()); 102 | world->add_component(rtr, 0); 103 | } 104 | } 105 | } 106 | 107 | // 测试 108 | Mob::Mob(World *world, SDL_FPoint p) 109 | { 110 | const std::u16string mob_id = u"1210102"; 111 | auto node = world->get_resource().Mob->get_root()->find_from_path(mob_id + u".img"); 112 | // 排除 link 113 | while (node->find_from_path(u"info/link") != nullptr) 114 | { 115 | auto link = dynamic_cast *>(node->find_from_path(u"info/link"))->get(); 116 | node = world->get_resource().Mob->get_root()->find_from_path(link + u".img"); 117 | } 118 | for (auto &[name, val] : node->get_children()) 119 | { 120 | if (name != u"info") 121 | { 122 | auto aspr = new AnimatedSprite(val[0]); 123 | aspr_map[name] = aspr; 124 | world->add_component(aspr); 125 | } 126 | } 127 | act = u"jump"; 128 | add_component(aspr_map[act]); 129 | 130 | Transform *tr = new Transform(p); 131 | add_component(tr); 132 | world->add_component(tr, 3000000); 133 | } 134 | 135 | void Mob::switch_act(const std::u16string &action) 136 | { 137 | if (action != act) 138 | { 139 | if (aspr_map.contains(action)) 140 | { 141 | auto aspr = aspr_map[action]; 142 | aspr->set_anim_index(0); 143 | aspr->set_anim_time(0); 144 | act = action; 145 | add_component(aspr); 146 | } 147 | } 148 | } 149 | 150 | void Mob::start_animate() 151 | { 152 | get_component()->set_animate(true); 153 | } 154 | 155 | void Mob::stop_animate() 156 | { 157 | get_component()->set_animate(false); 158 | } 159 | 160 | Mob::~Mob() 161 | { 162 | auto world = World::get_world(); 163 | 164 | for (auto &[key, val] : aspr_map) 165 | { 166 | auto aspr = val; 167 | world->destroy_component(aspr, false); 168 | delete aspr; 169 | } 170 | 171 | for (auto &[key, val] : get_entity()) 172 | { 173 | auto t = val->get_component(); 174 | auto rtr = val->get_component(); 175 | world->destroy_component(t, false); 176 | world->destroy_component(rtr, false); 177 | delete t; 178 | delete rtr; 179 | delete val; 180 | } 181 | 182 | for (auto &[key, val] : get_entity()) 183 | { 184 | auto t = val->get_component(); 185 | auto rtr = val->get_component(); 186 | world->destroy_component(t, false); 187 | world->destroy_component(rtr, false); 188 | delete t; 189 | delete rtr; 190 | delete val; 191 | } 192 | 193 | auto t = get_component(); 194 | world->destroy_component(t, false); 195 | delete t; 196 | 197 | auto nor = get_component(); 198 | if (nor != nullptr) 199 | { 200 | world->destroy_component(nor, false); 201 | delete nor; 202 | } 203 | 204 | auto ran = get_component(); 205 | if (ran != nullptr) 206 | { 207 | world->destroy_component(ran, false); 208 | delete ran; 209 | } 210 | 211 | auto ltr = get_component(); 212 | if (ltr != nullptr) 213 | { 214 | world->destroy_component(ltr, false); 215 | delete ltr; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /sdlms/Entities/Mob.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | #include "Components/AnimatedSprite.h" 7 | 8 | class Mob : public Entity 9 | { 10 | public: 11 | Mob(wz::Node *node, int id, int rx0, int rx1, World *world); 12 | Mob(World *world, SDL_FPoint p); 13 | ~Mob(); 14 | 15 | void switch_act(const std::u16string &action); 16 | void stop_animate(); 17 | void start_animate(); 18 | 19 | private: 20 | std::unordered_map aspr_map; 21 | std::unordered_map str_map; 22 | std::u16string act = u"jump"; 23 | }; -------------------------------------------------------------------------------- /sdlms/Entities/NameTag.cpp: -------------------------------------------------------------------------------- 1 | #include "NameTag.h" 2 | #include "Components/Sprite.h" 3 | #include "Resource/Wz.h" 4 | 5 | NameTag::NameTag(int width, int height) 6 | { 7 | width += 4; 8 | height += 6; 9 | auto renderer = Window::get_renderer(); 10 | Uint8 alpha = 178; 11 | Uint32 color = (alpha << 24) | (0 << 16) | (0 << 8) | 0; // ARGB格式,这里设置为纯黑色,透明度为178 12 | std::vector pixel(width * height); 13 | for (int i = 0; i < width * height; ++i) 14 | { 15 | pixel[i] = color; 16 | } 17 | auto texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); 18 | SDL_UpdateTexture(texture, NULL, pixel.data(), width * sizeof(Uint32)); 19 | SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 20 | 21 | Sprite *spr = new Sprite(texture, width, height); 22 | add_component(spr); 23 | } 24 | 25 | NameTag::NameTag(int width, int height, const std::u16string &val) 26 | { 27 | width += 4; 28 | height += 6; 29 | Sprite *spr = new Sprite(World::get_world()->get_resource().UI->get_root()->find_from_path(u"NameTag.img/" + val), 30 | width, height, Sprite::NameTag); 31 | add_component(spr); 32 | } 33 | 34 | int NameTag::get_width() 35 | { 36 | return get_component()->get_width(); 37 | } 38 | 39 | int NameTag::get_height() 40 | { 41 | return get_component()->get_height(); 42 | } 43 | 44 | NameTag::~NameTag() 45 | { 46 | auto spr = get_component(); 47 | delete spr; 48 | } 49 | -------------------------------------------------------------------------------- /sdlms/Entities/NameTag.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | 7 | class NameTag : public Entity 8 | { 9 | public: 10 | NameTag(int width, int height); 11 | NameTag(int width, int height, const std::u16string &val); 12 | int get_width(); 13 | int get_height(); 14 | 15 | ~NameTag(); 16 | }; 17 | -------------------------------------------------------------------------------- /sdlms/Entities/Npc.cpp: -------------------------------------------------------------------------------- 1 | #include "Npc.h" 2 | #include "FootHold.h" 3 | #include "NameTag.h" 4 | #include "String.h" 5 | #include "ChatBalloon.h" 6 | #include "Timer.h" 7 | 8 | #include "Components/Sprite.h" 9 | #include "Components/Transform.h" 10 | #include "Components/RelativeTransform.h" 11 | #include "Components/RandomInput.h" 12 | #include "Components/LimitTransform.h" 13 | #include "Components/Line.h" 14 | #include "Components/Physic/Normal.h" 15 | #include "Resource/Wz.h" 16 | 17 | Npc::Npc(wz::Node *node, int id, int rx0, int rx1, World *world) 18 | { 19 | if (node != nullptr) 20 | { 21 | auto npc_id = dynamic_cast *>(node->get_child(u"id"))->get(); 22 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 23 | auto fh = dynamic_cast *>(node->get_child(u"fh"))->get(); 24 | auto foo = world->get_entitys().find(fh)->second; 25 | // 从fh获取y,layer 26 | auto y = foo->get_component()->get_y(x).value(); 27 | auto layer = foo->get_page(); 28 | 29 | node = world->get_resource().Npc->get_root()->find_from_path(npc_id + u".img"); 30 | // 排除 link 31 | while (node->find_from_path(u"info/link") != nullptr) 32 | { 33 | auto link = dynamic_cast *>(node->find_from_path(u"info/link"))->get(); 34 | node = world->get_resource().Npc->get_root()->find_from_path(link + u".img"); 35 | } 36 | AnimatedSprite *aspr = nullptr; 37 | for (auto &[name, val] : node->get_children()) 38 | { 39 | if (name != u"info") 40 | { 41 | aspr = new AnimatedSprite(val[0]); 42 | aspr_map[name] = aspr; 43 | world->add_component(aspr); 44 | } 45 | } 46 | Transform *tr = new Transform{(float)x, (float)y}; 47 | add_component(tr); 48 | world->add_component(tr, layer * 300000 + id + 20000); 49 | 50 | if (aspr_map.size() > 0) 51 | { 52 | // 默认显示npc第一个状态 53 | act = aspr_map.begin()->first; 54 | auto aspr = aspr_map.begin()->second; 55 | add_component(aspr); 56 | } 57 | 58 | // 添加物理组件 59 | if (aspr_map.contains(u"move")) 60 | { 61 | Normal *nor = new Normal(); 62 | nor->type = Normal::Ground; 63 | add_entity(foo, 0); 64 | add_component(nor); 65 | world->add_component(nor); 66 | 67 | // 添加自动移动组件 68 | RandomInput *ran = new RandomInput(); 69 | add_component(ran); 70 | world->add_component(ran); 71 | 72 | // 添加移动范围 73 | LimitTransform *ltr = new LimitTransform(tr, SDL_FPoint{(float)rx0, (float)rx1}, std::nullopt); 74 | add_component(ltr); 75 | world->add_component(ltr); 76 | } 77 | // 从string.wz获取信息 78 | node = world->get_resource().String->get_root()->find_from_path(u"Npc.img/" + npc_id.substr(npc_id.find_first_not_of(u'0'))); 79 | if (node != nullptr) 80 | { 81 | int i = 0; 82 | for (auto &[key, val] : node->get_children()) 83 | { 84 | str_map[key] = dynamic_cast *>(val[0])->get(); 85 | if (key == u"name" || key == u"func") 86 | { 87 | auto str = new String(str_map[key], {255, 255, 0, 255}); 88 | add_entity(str); 89 | auto spr = str->get_component(); 90 | { 91 | auto nam = new NameTag(spr->width, spr->height); 92 | add_entity(nam); 93 | auto rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-spr->get_width() / 2), (float)(6 + (spr->get_height() + 6) * i)}); 94 | nam->add_component(rtr); 95 | nam->add_component(new Transform()); 96 | world->add_component(rtr, 0); 97 | } 98 | { 99 | auto rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-spr->get_width() / 2 + 2), (float)(9 + (spr->get_height() + 6) * i)}); 100 | str->add_component(rtr); 101 | str->add_component(new Transform()); 102 | world->add_component(rtr, 0); 103 | } 104 | i++; 105 | } 106 | else if (get_entity(0) == nullptr) 107 | { 108 | auto str = new String(str_map[key], {88, 0, 0, 255}, 8, 13); 109 | add_entity(str); 110 | 111 | // 添加聊天气泡 112 | auto bal = new ChatBalloon(str->get_width(), str->get_height(), u"0"); 113 | bal->add_entity(str); 114 | add_entity(bal); 115 | auto rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-bal->get_width() / 2), (float)-aspr->get_anim_height() - (aspr->get_current_sprite()->origin.y - aspr->get_anim_height()) - (float)bal->get_height()}); 116 | bal->add_component(rtr); 117 | bal->add_component(new Transform()); 118 | world->add_component(rtr, 0); 119 | 120 | auto callback = [](Uint32 interval, void *param) -> Uint32 121 | { 122 | auto world = World::get_world(); 123 | auto timer = (Timer *)param; 124 | auto bal = timer->get_entity(0); 125 | { 126 | auto spr = bal->get_component(); 127 | if (spr == nullptr) 128 | { 129 | bal->add_component(bal->spr); 130 | } 131 | else 132 | { 133 | bal->remove_component(); 134 | } 135 | } 136 | auto str = bal->get_entity(0); 137 | { 138 | auto spr = str->get_component(); 139 | if (spr == nullptr) 140 | { 141 | str->add_component(str->spr); 142 | } 143 | else 144 | { 145 | str->remove_component(); 146 | } 147 | } 148 | return 2000; 149 | }; 150 | Timer *timer = new Timer(callback, 2000); 151 | add_entity(timer); 152 | world->add_entity(timer); 153 | timer->add_entity(bal, 0); 154 | 155 | rtr = new RelativeTransform(tr, SDL_FPoint{(float)(-bal->get_width() / 2 + 8), (float)-aspr->get_anim_height() - (aspr->get_current_sprite()->origin.y - aspr->get_anim_height()) - (float)bal->get_height() + 6}); 156 | str->add_component(rtr); 157 | str->add_component(new Transform()); 158 | world->add_component(rtr, 0); 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | void Npc::switch_act(const std::u16string &action) 166 | { 167 | if (action != act) 168 | { 169 | if (aspr_map.contains(action)) 170 | { 171 | auto aspr = aspr_map[action]; 172 | aspr->set_anim_index(0); 173 | aspr->set_anim_time(0); 174 | act = action; 175 | add_component(aspr); 176 | } 177 | } 178 | } 179 | 180 | void Npc::start_animate() 181 | { 182 | get_component()->set_animate(true); 183 | } 184 | 185 | void Npc::stop_animate() 186 | { 187 | get_component()->set_animate(false); 188 | } 189 | 190 | Npc::~Npc() 191 | { 192 | auto world = World::get_world(); 193 | 194 | for (auto &[key, val] : aspr_map) 195 | { 196 | auto aspr = val; 197 | world->destroy_component(aspr, false); 198 | delete aspr; 199 | } 200 | 201 | for (auto &[key, val] : get_entity()) 202 | { 203 | auto t = val->get_component(); 204 | auto rtr = val->get_component(); 205 | world->destroy_component(t, false); 206 | world->destroy_component(rtr, false); 207 | delete t; 208 | delete rtr; 209 | delete val; 210 | } 211 | 212 | for (auto &[key, val] : get_entity()) 213 | { 214 | auto t = val->get_component(); 215 | auto rtr = val->get_component(); 216 | world->destroy_component(t, false); 217 | world->destroy_component(rtr, false); 218 | delete t; 219 | delete rtr; 220 | delete val; 221 | } 222 | 223 | for (auto &[key, val] : get_entity()) 224 | { 225 | auto t = val->get_component(); 226 | auto rtr = val->get_component(); 227 | world->destroy_component(t, false); 228 | world->destroy_component(rtr, false); 229 | delete t; 230 | delete rtr; 231 | delete val; 232 | } 233 | 234 | auto t = get_component(); 235 | world->destroy_component(t, false); 236 | delete t; 237 | 238 | auto nor = get_component(); 239 | if (nor != nullptr) 240 | { 241 | world->destroy_component(nor, false); 242 | delete nor; 243 | } 244 | 245 | auto ran = get_component(); 246 | if (ran != nullptr) 247 | { 248 | world->destroy_component(ran, false); 249 | delete ran; 250 | } 251 | 252 | auto ltr = get_component(); 253 | if (ltr != nullptr) 254 | { 255 | world->destroy_component(ltr, false); 256 | delete ltr; 257 | } 258 | 259 | for (auto &[key, val] : get_entity()) 260 | { 261 | world->remove_entity(val); 262 | delete val; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /sdlms/Entities/Npc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | #include "Components/AnimatedSprite.h" 7 | 8 | class Npc : public Entity 9 | { 10 | public: 11 | Npc(wz::Node *node, int id, int rx0, int rx1, World *world); 12 | ~Npc(); 13 | 14 | void switch_act(const std::u16string &action); 15 | void stop_animate(); 16 | void start_animate(); 17 | 18 | private: 19 | std::unordered_map aspr_map; 20 | std::unordered_map str_map; 21 | std::u16string act = u""; 22 | }; 23 | -------------------------------------------------------------------------------- /sdlms/Entities/Obj.cpp: -------------------------------------------------------------------------------- 1 | #include "Obj.h" 2 | #include "Components/AnimatedSprite.h" 3 | #include "Components/Transform.h" 4 | #include "Resource/Wz.h" 5 | 6 | Obj::Obj(wz::Node *node, int id, int layer, World *world) 7 | { 8 | auto oS = dynamic_cast *>(node->get_child(u"oS"))->get(); 9 | auto l0 = dynamic_cast *>(node->get_child(u"l0"))->get(); 10 | auto l1 = dynamic_cast *>(node->get_child(u"l1"))->get(); 11 | auto l2 = dynamic_cast *>(node->get_child(u"l2"))->get(); 12 | auto url = u"Obj/" + oS + u".img/" + l0 + u"/" + l1 + u"/" + l2; 13 | 14 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 15 | auto y = dynamic_cast *>(node->get_child(u"y"))->get(); 16 | auto z = dynamic_cast *>(node->get_child(u"z"))->get(); 17 | 18 | auto flip = dynamic_cast *>(node->get_child(u"f"))->get(); 19 | 20 | auto aspr = new AnimatedSprite(world->get_resource().Map->get_root()->find_from_path(url)); 21 | 22 | Transform *t = new Transform((float)x, (float)y, flip); 23 | 24 | add_component(t); 25 | add_component(aspr); 26 | world->add_component(t, layer * 300000 + z * 100 + id); 27 | world->add_component(aspr); 28 | } 29 | 30 | Obj::~Obj() 31 | { 32 | auto world = World::get_world(); 33 | 34 | auto aspr = get_component(); 35 | world->destroy_component(aspr, false); 36 | delete aspr; 37 | 38 | auto t = get_component(); 39 | world->destroy_component(t, false); 40 | delete t; 41 | } 42 | -------------------------------------------------------------------------------- /sdlms/Entities/Obj.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | 7 | class Obj : public Entity 8 | { 9 | public: 10 | Obj(wz::Node *node,int id,int layer, World *world); 11 | ~Obj(); 12 | }; 13 | -------------------------------------------------------------------------------- /sdlms/Entities/Portal.cpp: -------------------------------------------------------------------------------- 1 | #include "Portal.h" 2 | #include "Resource/Wz.h" 3 | #include "Components/Sprite.h" 4 | #include "Components/Transform.h" 5 | #include "Components/DistanceSprite.h" 6 | #include "Timer.h" 7 | 8 | Portal::Portal(wz::Node *node, World *world) 9 | { 10 | constexpr const char16_t *pt_list[] = {u"sp", u"pi", u"pv", u"pc", u"pg", u"tp", u"ps", 11 | u"pgi", u"psi", u"pcs", u"ph", u"psh", u"pcj", 12 | u"pci", u"pcig", u"pshg"}; 13 | if (node->get_child(u"pt") != nullptr) 14 | { 15 | 16 | pt = dynamic_cast *>(node->get_child(u"pt"))->get(); 17 | tm = dynamic_cast *>(node->get_child(u"tm"))->get(); 18 | pn = dynamic_cast *>(node->get_child(u"pn"))->get(); 19 | tn = dynamic_cast *>(node->get_child(u"tn"))->get(); 20 | 21 | if (pt < 0 || pt >= sizeof(pt_list)) 22 | { 23 | return; 24 | } 25 | else 26 | { 27 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 28 | auto y = dynamic_cast *>(node->get_child(u"y"))->get(); 29 | { 30 | 31 | // auto url = u"MapHelper.img/portal/editor/" + std::basic_string(pt_list[pt]); 32 | // auto pn = world->get_resource().Map->get_root()->find_from_path(url); 33 | // Sprite *spr = new Sprite(pn); 34 | // add_component(spr); 35 | Transform *t = new Transform{(float)x, (float)y}; 36 | add_component(t); 37 | world->add_component(t, 99999999); 38 | } 39 | 40 | { 41 | if (pt == 7) 42 | { 43 | pt = 2; 44 | } 45 | auto url = u"MapHelper.img/portal/game/" + std::basic_string(pt_list[pt]); 46 | if (world->get_resource().Map->get_root()->find_from_path(url) != NULL) 47 | { 48 | if (world->get_resource().Map->get_root()->find_from_path(url + u"/default") != NULL) 49 | { 50 | auto disspr = new DistanceSprite(); 51 | add_component(disspr); 52 | world->add_component(disspr); 53 | { 54 | auto aspr = new AnimatedSprite(world->get_resource().Map->get_root()->find_from_path(url + u"/default/portalContinue")); 55 | disspr->add(SDL_FPoint{-100, 100}, SDL_FPoint{-50, 50}, aspr); 56 | aspr_map[u"portalContinue"] = aspr; 57 | world->add_component(aspr); 58 | } 59 | { 60 | auto aspr = new AnimatedSprite(world->get_resource().Map->get_root()->find_from_path(url + u"/default/portalExit")); 61 | disspr->add(SDL_FPoint{-150, 150}, SDL_FPoint{-100, 100}, aspr); 62 | aspr_map[u"portalExit"] = aspr; 63 | world->add_component(aspr); 64 | } 65 | { 66 | auto aspr = new AnimatedSprite(world->get_resource().Map->get_root()->find_from_path(url + u"/default/portalStart")); 67 | disspr->add(std::nullopt, std::nullopt, std::nullopt); 68 | aspr_map[u"portalStart"] = aspr; 69 | world->add_component(aspr); 70 | } 71 | } 72 | else 73 | { 74 | // 普通的传送门,通常为pv 75 | auto aspr = new AnimatedSprite(world->get_resource().Map->get_root()->find_from_path(url)); 76 | add_component(aspr); 77 | world->add_component(aspr); 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | 85 | Portal::~Portal() 86 | { 87 | auto world = World::get_world(); 88 | 89 | if (aspr_map.size() > 0) 90 | { 91 | for (auto &[key, val] : aspr_map) 92 | { 93 | auto aspr = val; 94 | world->destroy_component(aspr, false); 95 | delete aspr; 96 | } 97 | } 98 | else if (get_component() != nullptr) 99 | { 100 | auto aspr = get_component(); 101 | if (aspr != nullptr) 102 | { 103 | world->destroy_component(aspr, false); 104 | delete aspr; 105 | } 106 | } 107 | 108 | auto spr = get_component(); 109 | if (spr != nullptr) 110 | { 111 | delete spr; 112 | } 113 | 114 | auto t = get_component(); 115 | if (t != nullptr) 116 | { 117 | world->destroy_component(t, false); 118 | delete t; 119 | } 120 | 121 | auto disspr = get_component(); 122 | if (disspr != nullptr) 123 | { 124 | world->destroy_component(disspr, false); 125 | delete disspr; 126 | } 127 | 128 | for (auto &[key, val] : get_entity()) 129 | { 130 | world->remove_entity(val); 131 | delete val; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /sdlms/Entities/Portal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | #include "Components/AnimatedSprite.h" 7 | 8 | class Portal : public Entity 9 | { 10 | public: 11 | Portal(wz::Node *node, World *world); 12 | ~Portal(); 13 | 14 | std::unordered_map aspr_map; 15 | int tm = 0; 16 | int pt = 0; 17 | std::u16string pn; 18 | std::u16string tn; 19 | }; 20 | -------------------------------------------------------------------------------- /sdlms/Entities/String.cpp: -------------------------------------------------------------------------------- 1 | #include "String.h" 2 | 3 | String::String(const std::u16string &s, SDL_Color color, int w, int size) 4 | { 5 | FreeType::size(size); 6 | spr = FreeType::str(s, color, w); 7 | add_component(spr); 8 | } 9 | 10 | int String::get_width() 11 | { 12 | return get_component()->get_width(); 13 | } 14 | 15 | int String::get_height() 16 | { 17 | return get_component()->get_height(); 18 | } 19 | 20 | String::~String() 21 | { 22 | delete spr; 23 | } 24 | -------------------------------------------------------------------------------- /sdlms/Entities/String.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | 7 | #include "Core/FreeType.h" 8 | 9 | class String : public Entity 10 | { 11 | public: 12 | String(const std::u16string &s, SDL_Color color = {255, 255, 255, 255}, int w = 0, int size = 12); 13 | int get_width(); 14 | int get_height(); 15 | ~String(); 16 | 17 | public: 18 | Sprite *spr; 19 | }; 20 | -------------------------------------------------------------------------------- /sdlms/Entities/Tile.cpp: -------------------------------------------------------------------------------- 1 | #include "Tile.h" 2 | #include "Components/Sprite.h" 3 | #include "Components/Transform.h" 4 | #include "Resource/Wz.h" 5 | #include 6 | #include 7 | 8 | Tile::Tile(wz::Node *node, const std::u16string &ts, int layer, int id, World *world) 9 | { 10 | auto u = dynamic_cast *>(node->get_child(u"u"))->get(); 11 | auto no = dynamic_cast *>(node->get_child(u"no"))->get(); 12 | auto x = dynamic_cast *>(node->get_child(u"x"))->get(); 13 | auto y = dynamic_cast *>(node->get_child(u"y"))->get(); 14 | 15 | auto no_str = std::to_string(no); 16 | 17 | auto url = u"Tile/" + ts + u".img/" + u + u"/" + std::u16string{no_str.begin(), no_str.end()}; 18 | 19 | Sprite *spr = new Sprite(world->get_resource().Map->get_root()->find_from_path(url)); 20 | Transform *t = new Transform{(float)x, (float)y}; 21 | add_component(t); 22 | add_component(spr); 23 | world->add_component(t, layer * 300000 + std::any_cast(spr->z) * 1000 + id + 10000); 24 | } 25 | 26 | Tile::~Tile() 27 | { 28 | auto world = World::get_world(); 29 | 30 | auto spr = get_component(); 31 | delete spr; 32 | 33 | auto t = get_component(); 34 | world->destroy_component(t, false); 35 | delete t; 36 | } 37 | -------------------------------------------------------------------------------- /sdlms/Entities/Tile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Entity.h" 4 | #include "wz/Property.hpp" 5 | #include "Core/World.h" 6 | 7 | class Tile : public Entity 8 | { 9 | public: 10 | Tile(wz::Node *node, const std::u16string &ts, int layer, int id, World *world); 11 | ~Tile(); 12 | }; 13 | -------------------------------------------------------------------------------- /sdlms/Entities/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "Timer.h" 2 | 3 | Timer::Timer(const std::function &callback, int time) : callback(callback), time(time) 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /sdlms/Entities/Timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Entity.h" 3 | #include 4 | 5 | class Timer : public Entity 6 | { 7 | public: 8 | Timer(const std::function &callback, int time); 9 | 10 | public: 11 | int time = 0; 12 | std::function callback; 13 | 14 | }; -------------------------------------------------------------------------------- /sdlms/Resource/Resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Resource 4 | { 5 | public: 6 | Resource(){}; 7 | virtual ~Resource(){}; 8 | 9 | private: 10 | unsigned long id; 11 | }; 12 | -------------------------------------------------------------------------------- /sdlms/Resource/Wz.cpp: -------------------------------------------------------------------------------- 1 | #include "Wz.h" 2 | 3 | #define U8 static_cast 4 | #define IV4(A, B, C, D) \ 5 | { \ 6 | U8(A), U8(B), U8(C), U8(D) \ 7 | } 8 | 9 | Wz::Wz(const std::string &filename_prefix) 10 | { 11 | const auto iv = IV4(0xb9, 0x7d, 0x63, 0xe9); 12 | // 默认全部加载 13 | // Base = (new wz::File(iv, (std::string(filename_prefix) + std::string("Base.wz")).c_str())); 14 | Character = (new wz::File(iv, (std::string(filename_prefix) + std::string("Character.wz")).c_str())); 15 | // Effect = (new wz::File(iv, (std::string(filename_prefix) + std::string("Effect.wz")).c_str())); 16 | // Etc = (new wz::File(iv, (std::string(filename_prefix) + std::string("Etc.wz")).c_str())); 17 | // Item = (new wz::File(iv, (std::string(filename_prefix) + std::string("Item.wz")).c_str())); 18 | // List = (new wz::File(iv, (std::string(filename_prefix) + std::string("List.wz")).c_str())); 19 | Map = (new wz::File(iv, (std::string(filename_prefix) + std::string("Map.wz")).c_str())); 20 | Mob = (new wz::File(iv, (std::string(filename_prefix) + std::string("Mob.wz")).c_str())); 21 | // Morph = (new wz::File(iv, (std::string(filename_prefix) + std::string("Morph.wz")).c_str())); 22 | Npc = (new wz::File(iv, (std::string(filename_prefix) + std::string("Npc.wz")).c_str())); 23 | // Quest = (new wz::File(iv, (std::string(filename_prefix) + std::string("Quest.wz")).c_str())); 24 | // Reactor = (new wz::File(iv, (std::string(filename_prefix) + std::string("Reactor.wz")).c_str())); 25 | // Skill = (new wz::File(iv, (std::string(filename_prefix) + std::string("Skill.wz")).c_str())); 26 | Sound = (new wz::File(iv, (std::string(filename_prefix) + std::string("Sound.wz")).c_str())); 27 | String = (new wz::File(iv, (std::string(filename_prefix) + std::string("String.wz")).c_str())); 28 | // TamingMob = (new wz::File(iv, (std::string(filename_prefix) + std::string("TamingMob.wz")).c_str())); 29 | UI = (new wz::File(iv, (std::string(filename_prefix) + std::string("UI.wz")).c_str())); 30 | 31 | // Base->parse(u"Base"); 32 | Character->parse(u"Character"); 33 | // Effect->parse(); 34 | // Etc->parse(); 35 | // Item->parse(); 36 | // List->parse(); 37 | Map->parse(u"Map"); 38 | Mob->parse(u"Mob"); 39 | // Morph->parse(); 40 | Npc->parse(u"Npc"); 41 | // Quest->parse(); 42 | // Reactor->parse(); 43 | // Skill->parse(); 44 | Sound->parse(u"Sound"); 45 | String->parse(u"String"); 46 | // TamingMob->parse(); 47 | UI->parse(u"UI"); 48 | } -------------------------------------------------------------------------------- /sdlms/Resource/Wz.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Resource.h" 4 | class Wz : public Resource 5 | { 6 | public: 7 | Wz(const std::string &filename_prefix); 8 | 9 | public: 10 | wz::File *Base; 11 | wz::File *Character; 12 | wz::File *Effect; 13 | wz::File *Etc; 14 | wz::File *Item; 15 | wz::File *List; 16 | wz::File *Map; 17 | wz::File *Mob; 18 | wz::File *Morph; 19 | wz::File *Npc; 20 | wz::File *Quest; 21 | wz::File *Reactor; 22 | wz::File *Skill; 23 | wz::File *Sound; 24 | wz::File *String; 25 | wz::File *TamingMob; 26 | wz::File *UI; 27 | }; 28 | -------------------------------------------------------------------------------- /sdlms/Systems/CameraSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "CameraSystem.h" 2 | #include "Entities/Border.h" 3 | #include 4 | 5 | void CameraSystem::run(World &world) 6 | { 7 | if (world.components_exist_of_type()) 8 | { 9 | auto camera = world.get_components().find(0)->second; 10 | update_camera(camera, camera->get_owner_component(), world); 11 | } 12 | } 13 | 14 | void CameraSystem::update_camera(Camera *cam, Transform *tr, World &world) 15 | { 16 | auto h_prev_x = cam->get_x(); // 上一帧摄像机坐标 17 | auto h_next_x = tr->get_position().x - cam->get_w() / 2; // 人物移动后新的摄像机坐标 18 | auto h_delta = h_next_x - h_prev_x; // 新的摄像机坐标与旧的摄像机坐标差值 19 | 20 | cam->set_x(std::lerp(h_prev_x, h_next_x, std::abs(h_delta) / 6000.0f)); 21 | 22 | auto v_prev_y = cam->get_y(); // 上一帧摄像机坐标 23 | auto v_next_y = tr->get_position().y - cam->get_h() / 2; // 人物移动后新的摄像机坐标 24 | auto v_delta = v_next_y - v_prev_y; // 新的摄像机坐标与旧的摄像机坐标差值 25 | 26 | cam->set_y(std::lerp(v_prev_y, v_next_y, std::abs(v_delta) / 6000.0f)); 27 | 28 | if (world.entity_exist_of_type()) 29 | { 30 | auto border = world.get_entitys().find(0)->second; 31 | auto left = border->get_left(); 32 | auto right = border->get_right(); 33 | auto top = border->get_top(); 34 | auto bottom = border->get_bottom(); 35 | 36 | if (left.has_value() && cam->get_x() < left.value()) 37 | { 38 | cam->set_x(left.value()); 39 | } 40 | else if (right.has_value() && cam->get_x() + cam->get_w() > right.value()) 41 | { 42 | cam->set_x(right.value() - cam->get_w()); 43 | } 44 | if (bottom.has_value() && cam->get_y() + cam->get_h() > bottom.value()) 45 | { 46 | cam->set_y(bottom.value() - cam->get_h()); 47 | } 48 | 49 | if (right.has_value() && left.has_value()) 50 | { 51 | if (right.value() - left.value() < cam->get_w()) 52 | { 53 | // 如果地图宽度小于摄像机宽度,地图居中显示 54 | cam->set_x(left.value() - (cam->get_w() - (right.value() - left.value())) / 2); 55 | } 56 | } 57 | if (bottom.has_value() && top.has_value()) 58 | { 59 | if (bottom.value() - top.value() < cam->get_h()) 60 | { 61 | // 如果地图高度小于摄像机高度,地图居中显示 62 | cam->set_y(top.value() - (cam->get_h() - (bottom.value() - top.value())) / 2); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sdlms/Systems/CameraSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Systems/System.h" 3 | #include "Components/Transform.h" 4 | #include "Components/Camera.h" 5 | 6 | class CameraSystem : public System 7 | { 8 | public: 9 | void run(World &world) override; 10 | 11 | private: 12 | void update_camera(Camera *cam, Transform *tr, World &world); 13 | }; 14 | -------------------------------------------------------------------------------- /sdlms/Systems/DeltaTimeSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "DeltaTimeSystem.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void DeltaTimeSystem::run(World &world) 7 | { 8 | auto delta_time = world.get_delta_time(); 9 | 10 | if (world.components_exist_of_type()) 11 | { 12 | for (auto &[index, aspr] : world.get_components()) 13 | { 14 | if (aspr->get_owner() != nullptr) 15 | { 16 | update_animated_sprite(aspr, delta_time, world); 17 | } 18 | } 19 | } 20 | if (world.components_exist_of_type()) 21 | { 22 | for (auto &[index, ava] : world.get_components()) 23 | { 24 | update_avatar(ava, delta_time, world); 25 | } 26 | } 27 | if (world.entity_exist_of_type()) 28 | { 29 | update_timer(delta_time, world); 30 | } 31 | } 32 | 33 | bool DeltaTimeSystem::update_animated_sprite(AnimatedSprite *aspr, int delta_time, World &world) 34 | { 35 | bool end = false; 36 | [[likely]] 37 | if (aspr->get_animate()) 38 | { 39 | aspr->add_anim_time(delta_time); 40 | if (aspr->get_anim_time() >= aspr->get_anim_delay()) 41 | { 42 | if (aspr->get_anim_index() == aspr->get_anim_size() - 1 && aspr->get_zigzag()) 43 | { 44 | std::ranges::reverse(aspr->get_sprites()); 45 | aspr->set_anim_index(1); 46 | } 47 | else 48 | { 49 | aspr->set_anim_index((aspr->get_anim_index() + 1) % aspr->get_anim_size()); 50 | } 51 | aspr->set_anim_time(0); 52 | end = true; 53 | } 54 | // 透明度处理 55 | auto a0 = aspr->get_current_sprite()->a0; 56 | auto a1 = aspr->get_current_sprite()->a1; 57 | [[unlikely]] 58 | if (a0 != a1) 59 | { 60 | auto alpha = 255; 61 | if (a0 <= a1) 62 | { 63 | alpha = (float)a0 + (float)(a1 - a0) / (float)aspr->get_current_sprite()->delay * (float)aspr->get_anim_time(); 64 | } 65 | else 66 | { 67 | alpha = (float)a0 - (float)(a0 - a1) / (float)aspr->get_current_sprite()->delay * (float)aspr->get_anim_time(); 68 | } 69 | SDL_SetTextureAlphaMod(aspr->get_current_sprite()->texture, alpha); 70 | } 71 | else 72 | { 73 | SDL_SetTextureAlphaMod(aspr->get_current_sprite()->texture, a0); 74 | } 75 | } 76 | return end; 77 | } 78 | 79 | void DeltaTimeSystem::update_avatar(Avatar *ava, int delta_time, World &world) 80 | { 81 | [[likely]] 82 | if (ava->animate) 83 | { 84 | auto delay = ava->stance_delays[ava->act][ava->act_index]; 85 | ava->act_time += delta_time; 86 | if (ava->act_time >= delay) 87 | { 88 | ava->act_index = (ava->act_index + 1) % ava->stance_delays[ava->act].size(); 89 | ava->act_time = 0; 90 | } 91 | } 92 | } 93 | 94 | void DeltaTimeSystem::update_timer(int delta_time, World &world) 95 | { 96 | auto &target_map = world.get_entitys(); 97 | for (auto it = target_map.begin(); it != target_map.end();) 98 | { 99 | it->second->time -= delta_time; 100 | if (it->second->time <= 0) 101 | { 102 | auto time = it->second->callback(0, it->second); 103 | if (time > 0) 104 | { 105 | it->second->time = time; 106 | } 107 | else 108 | { 109 | it = target_map.erase(it); 110 | continue; 111 | } 112 | } 113 | ++it; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /sdlms/Systems/DeltaTimeSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Systems/System.h" 3 | #include "Components/AnimatedSprite.h" 4 | #include "Components/Transform.h" 5 | #include "Components/HVMove.h" 6 | #include "Components/Avatar.h" 7 | #include "Components/Video.h" 8 | 9 | #include "Entities/Timer.h" 10 | 11 | class DeltaTimeSystem : public System 12 | { 13 | public: 14 | void run(World &world) override; 15 | 16 | private: 17 | bool update_animated_sprite(AnimatedSprite *aspr, int delta_time, World &world); 18 | void update_avatar(Avatar *hvm, int delta_time, World &world); 19 | void update_timer(int delta_time, World &world); 20 | }; 21 | -------------------------------------------------------------------------------- /sdlms/Systems/InputSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "InputSystem.h" 2 | #include "Core/Input.h" 3 | #include "Components/Avatar.h" 4 | #include "SDL_keycode.h" 5 | 6 | void InputSystem::run(World &world) 7 | { 8 | if (world.components_exist_of_type()) 9 | { 10 | for (auto &[index, pla] : world.get_components()) 11 | { 12 | update_player(pla, world); 13 | } 14 | } 15 | if (world.components_exist_of_type()) 16 | { 17 | for (auto &[index, ran] : world.get_components()) 18 | { 19 | update_random_input(ran, world); 20 | } 21 | } 22 | } 23 | 24 | void InputSystem::update_player(Player *pla, World &world) 25 | { 26 | auto nor = pla->get_owner_component(); 27 | auto ava = pla->get_owner_component(); 28 | auto tr = pla->get_owner_component(); 29 | 30 | nor->vkey = Normal::None; 31 | nor->hkey = Normal::None; 32 | nor->lalt = false; 33 | nor->lctrl = false; 34 | 35 | // 判断是否有h或v方向输入 36 | if (Input::is_key_held(SDLK_RIGHT)) 37 | { 38 | nor->hkey = Normal::Right; 39 | } 40 | else if (Input::is_key_held(SDLK_LEFT)) 41 | { 42 | nor->hkey = Normal::Left; 43 | } 44 | if (Input::is_key_held(SDLK_UP)) 45 | { 46 | nor->vkey = Normal::Up; 47 | } 48 | else if (Input::is_key_held(SDLK_DOWN)) 49 | { 50 | nor->vkey = Normal::Down; 51 | } 52 | if (Input::is_key_held(SDLK_LALT)) 53 | { 54 | nor->lalt = true; 55 | } 56 | if (Input::is_key_held(SDLK_LCTRL)) 57 | { 58 | nor->lctrl = true; 59 | } 60 | } 61 | 62 | void InputSystem::update_random_input(RandomInput *ran, World &world) 63 | { 64 | auto tick = ran->get_tick(); 65 | if (tick > ran->get_count()) 66 | { 67 | constexpr uint8_t types[] = {Normal::None, Normal::Left, Normal::Right}; 68 | auto num = types[std::rand() % std::size(types)]; 69 | ran->get_owner_component()->hkey = num; 70 | // ran->get_owner_component()->hkey = Normal::Left; 71 | ran->set_tick(0); 72 | } 73 | else 74 | { 75 | ran->set_tick(ran->get_tick() + 1); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /sdlms/Systems/InputSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Systems/System.h" 3 | #include "Components/Transform.h" 4 | #include "Components/Physic/Normal.h" 5 | #include "Components/Player.h" 6 | #include "Components/RandomInput.h" 7 | 8 | class InputSystem : public System 9 | { 10 | public: 11 | void run(World &world) override; 12 | 13 | private: 14 | void update_player(Player *nor, World &world); 15 | void update_random_input(RandomInput *ran, World &world); 16 | }; 17 | -------------------------------------------------------------------------------- /sdlms/Systems/PhysicSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Systems/System.h" 3 | #include "Components/Transform.h" 4 | #include "Components/Physic/Normal.h" 5 | #include 6 | #include 7 | 8 | class PhysicSystem : public System 9 | { 10 | public: 11 | PhysicSystem(){}; 12 | ~PhysicSystem() = default; 13 | void run(World &world) override; 14 | 15 | private: 16 | void update_normal(Normal *nor, World &world); 17 | bool want_climb(Transform *tr, Normal *nor, World &world); 18 | bool want_prone(Normal *nor, World &world); 19 | bool want_fall(Transform *tr, Normal *nor, World &world); 20 | bool want_stand(Normal *nor, World &world); 21 | bool want_jump(Transform *tr, Normal *nor, World &world); 22 | bool want_attack(Transform *tr, Normal *nor, World &world); 23 | bool want_portal(Transform *tr, Normal *nor, World &world); 24 | bool walk(Transform *tr, Normal *nor, World &world, float delta_time); 25 | void fall(Transform *tr, Normal *nor, float delta_time, World &world); 26 | void climb(Transform *tr, Normal *nor, float delta_time); 27 | inline std::optional intersect(SDL_FPoint p1, 28 | SDL_FPoint p2, 29 | SDL_FPoint p3, 30 | SDL_FPoint p4); 31 | }; 32 | -------------------------------------------------------------------------------- /sdlms/Systems/RenderSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderSystem.h" 2 | 3 | #include "Core/World.h" 4 | #include "Core/ECSSystem.h" 5 | #include "Components/Camera.h" 6 | #include "Components/Avatar.h" 7 | 8 | void RenderSystem::run(World &world) 9 | { 10 | if (world.components_exist_of_type()) 11 | { 12 | for (auto &[index, tr] : world.get_components()) 13 | { 14 | if (tr->get_owner_component() != nullptr) 15 | { 16 | render_hvtile_sprite(tr, tr->get_owner_component(), world); 17 | } 18 | else if (tr->get_owner_component() != nullptr) 19 | { 20 | render_avatar_sprite(tr, tr->get_owner_component(), world); 21 | } 22 | else if (tr->get_owner_component() != nullptr) 23 | { 24 | render_animated_sprite(tr, tr->get_owner_component(), world); 25 | } 26 | else if (tr->get_owner_component() != nullptr) 27 | { 28 | render_sprite(tr, tr->get_owner_component(), world); 29 | } 30 | else if (tr->get_owner_component