乒乓球游戏:C++ GDExtension 实现
这个提交包含在:
+10
-6
@@ -1,12 +1,16 @@
|
|||||||
# Godot 4+ specific ignores
|
# Godot 项目文件
|
||||||
.godot/
|
main/.godot/
|
||||||
/android/
|
main/android/
|
||||||
|
|
||||||
# C++ 扩展编译产物
|
# C++ 编译产物
|
||||||
/build/
|
build/
|
||||||
/bin/
|
main/bin/
|
||||||
|
|
||||||
|
# IDE
|
||||||
*.user
|
*.user
|
||||||
*.suo
|
*.suo
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
# 其他
|
# 其他
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
[docks]
|
||||||
|
|
||||||
|
dock_3_selected_tab_idx=0
|
||||||
|
dock_4_selected_tab_idx=0
|
||||||
|
dock_5_selected_tab_idx=0
|
||||||
|
dock_floating={}
|
||||||
|
dock_closed=[]
|
||||||
|
dock_split_2=0
|
||||||
|
dock_split_3=0
|
||||||
|
dock_hsplit_1=0
|
||||||
|
dock_hsplit_2=280
|
||||||
|
dock_hsplit_3=-280
|
||||||
|
dock_hsplit_4=0
|
||||||
|
dock_3="Scene,Import"
|
||||||
|
dock_4="FileSystem,History"
|
||||||
|
dock_5="Inspector,Signals,Groups"
|
||||||
|
dock_9="Output,Debugger,Audio,Animation,Shader Editor,Search Results,AnimationTree,ResourcePreloader,ShaderFile,SpriteFrames,Theme,Polygon,TileSet,TileMap,Replication,GridMap"
|
||||||
|
|
||||||
|
[docks/FileSystem]
|
||||||
|
|
||||||
|
h_split_offset=300
|
||||||
|
v_split_offset=0
|
||||||
|
display_mode=0
|
||||||
|
file_sort=0
|
||||||
|
file_list_display_mode=1
|
||||||
|
selected_paths=PackedStringArray("res://")
|
||||||
|
uncollapsed_paths=PackedStringArray("Favorites", "res://")
|
||||||
|
|
||||||
|
[docks/History]
|
||||||
|
|
||||||
|
include_scene=true
|
||||||
|
include_global=true
|
||||||
|
|
||||||
|
[EditorNode]
|
||||||
|
|
||||||
|
open_scenes=PackedStringArray()
|
||||||
|
current_scene=""
|
||||||
|
bottom_panel_offsets={
|
||||||
|
"Animation": 0,
|
||||||
|
"Audio": -450,
|
||||||
|
"Debugger": 0,
|
||||||
|
"Output": 0,
|
||||||
|
"Shader Editor": 0
|
||||||
|
}
|
||||||
|
selected_default_debugger_tab_idx=0
|
||||||
|
selected_main_editor_idx=0
|
||||||
|
|
||||||
|
[EditorWindow]
|
||||||
|
|
||||||
|
screen=0
|
||||||
|
mode="maximized"
|
||||||
|
position=Vector2i(0, 45)
|
||||||
|
|
||||||
|
[ScriptEditor]
|
||||||
|
|
||||||
|
open_scripts=[]
|
||||||
|
selected_script=""
|
||||||
|
open_help=[]
|
||||||
|
script_split_offset=250
|
||||||
|
list_split_offset=0
|
||||||
|
zoom_factor=1.0
|
||||||
|
|
||||||
|
[GameView]
|
||||||
|
|
||||||
|
floating_window_rect=Rect2i(0, 0, 0, 0)
|
||||||
|
floating_window_screen=-1
|
||||||
|
|
||||||
|
[ShaderEditor]
|
||||||
|
|
||||||
|
open_shaders=[]
|
||||||
|
split_offset=250
|
||||||
|
selected_shader=""
|
||||||
|
text_shader_zoom_factor=1.0
|
||||||
二进制文件未显示。
@@ -0,0 +1,3 @@
|
|||||||
|
[folding]
|
||||||
|
|
||||||
|
sections_unfolded=PackedStringArray()
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
63f7b34db8d8cdea90c76aacccf841ec
|
||||||
|
::res://::1770910434
|
||||||
|
icon.svg::CompressedTexture2D::1032248987546973613::1770899576::1770899582::1::::<><><>0<>0<>a844cc33f2422ec468dcd6fc2526be58<>res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex::
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[game_view]
|
||||||
|
|
||||||
|
select_mode=0
|
||||||
|
|
||||||
|
[editor_metadata]
|
||||||
|
|
||||||
|
executable_path="F:/Godot_v4.6-stable_win64.exe"
|
||||||
|
|
||||||
|
[dialog_bounds]
|
||||||
|
|
||||||
|
create_new_node=Rect2(397, 162, 1624, 875)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
list=[]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
source_md5="a16f2eed1b4496c4abf03d329708ba09"
|
||||||
|
dest_md5="b48bef1f2eefdd190e0a3e60a6188d75"
|
||||||
|
|
||||||
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制文件未显示。
@@ -0,0 +1,84 @@
|
|||||||
|
# Pingpang
|
||||||
|
|
||||||
|
乒乓球对战游戏 — Godot 4.6 + C++ GDExtension
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
pingpang/
|
||||||
|
├── CMakeLists.txt # CMake 构建配置
|
||||||
|
├── build-pingpang.bat # Windows 一键编译脚本
|
||||||
|
├── godot-cpp/ # Godot C++ 绑定(git submodule, 4.5 分支)
|
||||||
|
├── src/ # C++ 源码
|
||||||
|
│ ├── register_types.cpp/h # GDExtension 入口 + 类注册
|
||||||
|
│ ├── pingpong_ball.cpp/h # 球(移动、碰撞、得分检测)
|
||||||
|
│ ├── pingpong_paddle.cpp/h # 球拍(玩家输入 / AI)
|
||||||
|
│ └── pingpong_game.cpp/h # 游戏管理(计分、状态)
|
||||||
|
├── main/ # Godot 项目目录
|
||||||
|
│ ├── project.godot # Godot 项目配置
|
||||||
|
│ ├── pingpang.gdextension # GDExtension 加载配置
|
||||||
|
│ ├── scenes/
|
||||||
|
│ │ └── main.tscn # 主场景
|
||||||
|
│ ├── bin/ # 编译产物(gitignore)
|
||||||
|
│ │ └── pingpang.dll
|
||||||
|
│ └── .godot/ # Godot 编辑器数据(gitignore)
|
||||||
|
└── bin/ # 历史遗留(即将清理)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发环境
|
||||||
|
|
||||||
|
| 工具 | 版本/路径 |
|
||||||
|
|---|---|
|
||||||
|
| Godot 编辑器 | 4.6 (`F:/PCL/MyDownload/Godot_v4.6-stable_win64.exe`) |
|
||||||
|
| CMake | VS 2026 自带 |
|
||||||
|
| Visual Studio | 2026 (`D:/Visual Studio/`) |
|
||||||
|
| godot-cpp | 4.5 分支 |
|
||||||
|
|
||||||
|
## 编译 & 运行
|
||||||
|
|
||||||
|
### 编译 C++ 扩展
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows: 双击运行
|
||||||
|
build-pingpang.bat
|
||||||
|
|
||||||
|
# 或手动
|
||||||
|
cmake -S . -B build -G "Visual Studio 18 2026" -A x64
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
编译产物 `pingpang.dll` 会自动输出到 `main/bin/`。
|
||||||
|
|
||||||
|
### 打开 Godot 项目
|
||||||
|
|
||||||
|
1. 启动 Godot 4.6 编辑器
|
||||||
|
2. 导入项目 → 选择 `main/` 目录
|
||||||
|
3. 打开后直接按 F5 运行
|
||||||
|
|
||||||
|
## 核心类说明
|
||||||
|
|
||||||
|
### PingPongBall (CharacterBody2D)
|
||||||
|
- `speed: float` — 球速(默认 400)
|
||||||
|
- `reset()` — 重置到屏幕中央,随机方向发射
|
||||||
|
- `scored(which: int)` 信号 — 0=左边得分, 1=右边得分
|
||||||
|
|
||||||
|
### PingPongPaddle (CharacterBody2D)
|
||||||
|
- `speed: float` — 移动速度(默认 350)
|
||||||
|
- `is_player: bool` — true=玩家控制, false=AI
|
||||||
|
- `ball_path: NodePath` — AI 模式下追踪的球节点
|
||||||
|
|
||||||
|
### PingPongGame (Node2D)
|
||||||
|
- `left_score: int` / `right_score: int` — 当前比分
|
||||||
|
- `max_score: int` — 获胜分数(默认 5)
|
||||||
|
- `game_over(winner: int)` 信号 — 0=左边赢, 1=右边赢
|
||||||
|
|
||||||
|
## 协作指南
|
||||||
|
|
||||||
|
1. **添加新的 GDExtension 类**:
|
||||||
|
- 在 `src/` 创建 `.cpp`/`.h` 文件
|
||||||
|
- 在 `src/register_types.cpp` 中 `GDREGISTER_CLASS()`
|
||||||
|
- 在 `CMakeLists.txt` 的 `add_library()` 中添加源文件
|
||||||
|
|
||||||
|
2. **场景编辑**:在 Godot 编辑器中编辑 `main/scenes/main.tscn`,所有 C++ 类可在节点列表中直接创建
|
||||||
|
|
||||||
|
3. **提交代码前**:确保 `build-pingpang.bat` 编译通过
|
||||||
+20
-17
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.24)
|
cmake_minimum_required(VERSION 3.24)
|
||||||
project(marry)
|
project(pingpang)
|
||||||
|
|
||||||
# 标准 C++17
|
# 标准 C++17
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
@@ -11,31 +11,34 @@ set(GODOT_CPP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/godot-cpp")
|
|||||||
add_subdirectory("${GODOT_CPP_PATH}")
|
add_subdirectory("${GODOT_CPP_PATH}")
|
||||||
|
|
||||||
# 扩展库本体
|
# 扩展库本体
|
||||||
add_library(marry SHARED
|
add_library(pingpang SHARED
|
||||||
src/register_types.cpp
|
src/register_types.cpp
|
||||||
src/example.cpp
|
|
||||||
src/example.h
|
|
||||||
src/register_types.h
|
src/register_types.h
|
||||||
|
src/pingpong_ball.cpp
|
||||||
|
src/pingpong_ball.h
|
||||||
|
src/pingpong_paddle.cpp
|
||||||
|
src/pingpong_paddle.h
|
||||||
|
src/pingpong_game.cpp
|
||||||
|
src/pingpong_game.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(marry PRIVATE src)
|
target_include_directories(pingpang PRIVATE src)
|
||||||
|
|
||||||
# 链接 godot-cpp
|
# 链接 godot-cpp
|
||||||
target_link_libraries(marry PRIVATE godot-cpp)
|
target_link_libraries(pingpang PRIVATE godot-cpp)
|
||||||
|
|
||||||
# 输出到 bin/ 目录(Godot 从那里加载;VS 里编译后 dll 直接落到 res://bin/)
|
# 输出到 main/bin/ 目录(Godot 项目从这里加载 GDExtension)
|
||||||
set_target_properties(marry PROPERTIES
|
set_target_properties(pingpang PROPERTIES
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/main/bin"
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/main/bin"
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/main/bin"
|
||||||
PREFIX ""
|
PREFIX ""
|
||||||
)
|
)
|
||||||
|
|
||||||
# VS 多配置生成器会输出到 bin/Release/ 等子目录,这里复制到 bin/ 根目录
|
# VS 多配置生成器会输出到子目录,这里复制到 main/bin/ 根目录
|
||||||
# 保证 .gdextension 里 res://bin/marry.dll 始终能找到
|
add_custom_command(TARGET pingpang POST_BUILD
|
||||||
add_custom_command(TARGET marry POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
"$<TARGET_FILE:marry>"
|
"$<TARGET_FILE:pingpang>"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/bin/marry.dll"
|
"${CMAKE_CURRENT_SOURCE_DIR}/main/bin/$<TARGET_FILE_NAME:pingpang>"
|
||||||
COMMENT "复制 marry.dll 到 bin/ 根目录"
|
COMMENT "复制 pingpang.dll 到 main/bin/ 根目录"
|
||||||
)
|
)
|
||||||
|
|||||||
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制
二进制文件未显示。
某些文件未显示,因为此 diff 中更改的文件太多 显示更多
在新工单中引用
屏蔽一个用户