diff --git a/.gitmodules b/.gitmodules index 65294b3..d8a7489 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "cpp/simple/godot-cpp"] path = cpp/simple/godot-cpp url = https://github.com/godotengine/godot-cpp.git +[submodule "cpp/pong/godot-cpp"] + path = cpp/pong/godot-cpp + url = https://github.com/godotengine/godot-cpp.git diff --git a/cpp/pong/README.md b/cpp/pong/README.md new file mode 100644 index 0000000..c409c10 --- /dev/null +++ b/cpp/pong/README.md @@ -0,0 +1,44 @@ +# Pong with GDNative C++ + +A simple Pong game, made with GDNative C++. This demo shows best practices +for game development in Godot, including +[signals](https://docs.godotengine.org/en/latest/getting_started/step_by_step/signals.html). + +Language: C++ + +Renderer: GLES 2 + +Note: There is a GDScript version available [here](https://github.com/godotengine/godot-demo-projects/tree/master/2d/pong). + +Note: There is a C# version available [here](https://github.com/godotengine/godot-demo-projects/tree/master/mono/pong). + +Note: There is a VisualScript version available [here](https://github.com/godotengine/godot-demo-projects/tree/master/visual_script/pong). + +## Compiling + +You can use SCons to compile the library: + +``` +scons platform=PLATFORM +``` + +Where PLATFORM is: `windows`, `linux`, or `osx`. + +This creates the file `libsimple` in the respective +subfolders in the `project/gdnative` directory. + +Dependencies: + * You need [godot-cpp](https://github.com/godotengine/godot-cpp), + this is now a Git submodule of this repo. + * `clang`, `gcc`, or any decent C compiler that's C++14 compatible. + +## How does it work? + +The walls, paddle, and ball are all +[`Area2D`](https://docs.godotengine.org/en/latest/classes/class_area2d.html) +nodes. When the ball touches the walls or the paddles, +they emit signals and modify the ball. + +## Screenshots + +![Screenshot](screenshots/pong.png) diff --git a/cpp/pong/SConstruct b/cpp/pong/SConstruct new file mode 100644 index 0000000..71ac6e7 --- /dev/null +++ b/cpp/pong/SConstruct @@ -0,0 +1,111 @@ +#!python +import os + +opts = Variables([], ARGUMENTS) + +# Gets the standard flags CC, CCX, etc. +env = DefaultEnvironment() + +godot_headers_path = "godot-cpp/godot-headers" +godot_bindings_path = "godot-cpp" + +# Define our options. Use future-proofed names for platforms. +platform_array = ["", "windows", "linuxbsd", "macos", "x11", "linux", "osx"] +opts.Add(EnumVariable("target", "Compilation target", "debug", ["d", "debug", "r", "release"])) +opts.Add(EnumVariable("platform", "Compilation platform", "", platform_array)) +opts.Add(EnumVariable("p", "Alias for 'platform'", "", platform_array)) +opts.Add(BoolVariable("use_llvm", "Use the LLVM / Clang compiler", "no")) +opts.Add(PathVariable("target_path", "The path where the lib is installed.", "project/gdnative/")) +opts.Add(PathVariable("target_name", "The library name.", "libpong", PathVariable.PathAccept)) + +# Updates the environment with the option variables. +opts.Update(env) + +# Process platform arguments. Here we use the same names as GDNative. +if env["p"] != "": + env["platform"] = env["p"] + +if env["platform"] == "macos": + env["platform"] = "osx" +elif env["platform"] in ("x11", "linuxbsd"): + env["platform"] = "linux" +elif env["platform"] == "bsd": + env["platform"] = "freebsd" + +if env["platform"] == "": + print("No valid target platform selected.") + quit() + +platform = env["platform"] + +# Process other arguments. +if env["platform"] == "osx" and not env["use_llvm"]: + env["use_llvm"] = "yes" + +if env["use_llvm"] == "yes": + env["CC"] = "clang" + env["CXX"] = "clang++" + +# put stuff that is the same for all first, saves duplication +if env["platform"] == "osx": + if env["target"] in ("debug", "d"): + env.Append(CCFLAGS=["-g", "-O2", "-arch", "x86_64", "-std=c++14"]) + env.Append(LINKFLAGS=["-arch", "x86_64"]) + else: + env.Append(CCFLAGS=["-g", "-O3", "-arch", "x86_64", "-std=c++14"]) + env.Append(LINKFLAGS=["-arch", "x86_64"]) +elif env["platform"] == "linux": + if env["target"] in ("debug", "d"): + env.Append(CCFLAGS=["-fPIC", "-g3", "-Og"]) + else: + env.Append(CCFLAGS=["-fPIC", "-g", "-O3"]) +elif env["platform"] == "windows": + # This makes sure to keep the session environment variables + # on Windows, so that you can run scons in a VS 2017 prompt + # and it will find all the required tools. + env = Environment(ENV=os.environ) + opts.Update(env) + + env.Append(CCFLAGS=["-DWIN32", "-D_WIN32", "-D_WINDOWS", "-W3", "-GR", "-D_CRT_SECURE_NO_WARNINGS"]) + if env["target"] in ("debug", "d"): + env.Append(CCFLAGS=["-EHsc", "-D_DEBUG", "-MDd"]) + else: + env.Append(CCFLAGS=["-O2", "-EHsc", "-DNDEBUG", "-MD"]) + +SConscript("godot-cpp/SConstruct") + + +def add_sources(sources, dir): + for f in os.listdir(dir): + if f.endswith(".cpp"): + sources.append(dir + "/" + f) + + +env.Append( + CPPPATH=[ + godot_headers_path, + godot_bindings_path + "/include", + godot_bindings_path + "/include/gen/", + godot_bindings_path + "/include/core/", + ] +) + +env.Append( + LIBS=[ + env.File( + os.path.join( + "godot-cpp/bin", "libgodot-cpp.%s.%s.64%s" % (env["platform"], env["target"], env["LIBSUFFIX"]) + ) + ) + ] +) + +env.Append(LIBPATH=[godot_bindings_path + "/bin/"]) + +sources = [] +add_sources(sources, "src") + +library = env.SharedLibrary( + target=env["target_path"] + "/" + env["platform"] + "/" + env["target_name"], source=sources +) +Default(library) diff --git a/cpp/pong/project/ball.png b/cpp/pong/project/ball.png new file mode 100644 index 0000000..465d352 Binary files /dev/null and b/cpp/pong/project/ball.png differ diff --git a/cpp/pong/project/ball.png.import b/cpp/pong/project/ball.png.import new file mode 100644 index 0000000..f239f23 --- /dev/null +++ b/cpp/pong/project/ball.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/ball.png-9a4ca347acb7532f6ae347744a6b04f7.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://ball.png" +dest_files=[ "res://.import/ball.png-9a4ca347acb7532f6ae347744a6b04f7.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/cpp/pong/project/gdnative/linux/.gitignore b/cpp/pong/project/gdnative/linux/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/cpp/pong/project/gdnative/linux/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/cpp/pong/project/gdnative/osx/.gitignore b/cpp/pong/project/gdnative/osx/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/cpp/pong/project/gdnative/osx/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/cpp/pong/project/gdnative/pong.gdnlib b/cpp/pong/project/gdnative/pong.gdnlib new file mode 100644 index 0000000..f9821f3 --- /dev/null +++ b/cpp/pong/project/gdnative/pong.gdnlib @@ -0,0 +1,18 @@ +[general] + +singleton=false +load_once=true +symbol_prefix="godot_" +reloadable=true + +[entry] + +Windows.64="res://gdnative/windows/libpong.dll" +X11.64="res://gdnative/linux/libpong.so" +OSX.64="res://gdnative/osx/libpong.dylib" + +[dependencies] + +Windows.64=[ ] +X11.64=[ ] +OSX.64=[ ] diff --git a/cpp/pong/project/gdnative/windows/.gitignore b/cpp/pong/project/gdnative/windows/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/cpp/pong/project/gdnative/windows/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/cpp/pong/project/icon.png b/cpp/pong/project/icon.png new file mode 100644 index 0000000..b62e834 Binary files /dev/null and b/cpp/pong/project/icon.png differ diff --git a/cpp/pong/project/icon.png.import b/cpp/pong/project/icon.png.import new file mode 100644 index 0000000..96cbf46 --- /dev/null +++ b/cpp/pong/project/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/cpp/pong/project/logic/ball.gdns b/cpp/pong/project/logic/ball.gdns new file mode 100644 index 0000000..8505cd8 --- /dev/null +++ b/cpp/pong/project/logic/ball.gdns @@ -0,0 +1,9 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/pong.gdnlib" type="GDNativeLibrary" id=1] + +[resource] + +resource_name = "Ball" +class_name = "Ball" +library = ExtResource( 1 ) diff --git a/cpp/pong/project/logic/ceiling_floor.gdns b/cpp/pong/project/logic/ceiling_floor.gdns new file mode 100644 index 0000000..a9dc131 --- /dev/null +++ b/cpp/pong/project/logic/ceiling_floor.gdns @@ -0,0 +1,9 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/pong.gdnlib" type="GDNativeLibrary" id=1] + +[resource] + +resource_name = "CeilingFloor" +class_name = "CeilingFloor" +library = ExtResource( 1 ) diff --git a/cpp/pong/project/logic/paddle.gdns b/cpp/pong/project/logic/paddle.gdns new file mode 100644 index 0000000..3199437 --- /dev/null +++ b/cpp/pong/project/logic/paddle.gdns @@ -0,0 +1,9 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/pong.gdnlib" type="GDNativeLibrary" id=1] + +[resource] + +resource_name = "Paddle" +class_name = "Paddle" +library = ExtResource( 1 ) diff --git a/cpp/pong/project/logic/wall.gdns b/cpp/pong/project/logic/wall.gdns new file mode 100644 index 0000000..17919f3 --- /dev/null +++ b/cpp/pong/project/logic/wall.gdns @@ -0,0 +1,9 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/pong.gdnlib" type="GDNativeLibrary" id=1] + +[resource] + +resource_name = "Wall" +class_name = "Wall" +library = ExtResource( 1 ) diff --git a/cpp/pong/project/paddle.png b/cpp/pong/project/paddle.png new file mode 100644 index 0000000..1860b07 Binary files /dev/null and b/cpp/pong/project/paddle.png differ diff --git a/cpp/pong/project/paddle.png.import b/cpp/pong/project/paddle.png.import new file mode 100644 index 0000000..3363f63 --- /dev/null +++ b/cpp/pong/project/paddle.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://paddle.png" +dest_files=[ "res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/cpp/pong/project/pong.tscn b/cpp/pong/project/pong.tscn new file mode 100644 index 0000000..0adf026 --- /dev/null +++ b/cpp/pong/project/pong.tscn @@ -0,0 +1,107 @@ +[gd_scene load_steps=12 format=2] + +[ext_resource path="res://logic/paddle.gdns" type="Script" id=1] +[ext_resource path="res://paddle.png" type="Texture" id=2] +[ext_resource path="res://logic/ball.gdns" type="Script" id=4] +[ext_resource path="res://ball.png" type="Texture" id=5] +[ext_resource path="res://separator.png" type="Texture" id=6] +[ext_resource path="res://logic/wall.gdns" type="Script" id=7] +[ext_resource path="res://logic/ceiling_floor.gdns" type="Script" id=8] + +[sub_resource type="RectangleShape2D" id=1] +extents = Vector2( 4, 16 ) + +[sub_resource type="RectangleShape2D" id=2] +extents = Vector2( 4, 4 ) + +[sub_resource type="RectangleShape2D" id=3] +extents = Vector2( 10, 200 ) + +[sub_resource type="RectangleShape2D" id=4] +extents = Vector2( 320, 10 ) + +[node name="Pong" type="Node2D"] + +[node name="Background" type="ColorRect" parent="."] +margin_right = 640.0 +margin_bottom = 400.0 +color = Color( 0.141176, 0.152941, 0.164706, 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Left" type="Area2D" parent="."] +modulate = Color( 0, 1, 1, 1 ) +position = Vector2( 67.6285, 192.594 ) +script = ExtResource( 1 ) + +[node name="Sprite" type="Sprite" parent="Left"] +texture = ExtResource( 2 ) + +[node name="Collision" type="CollisionShape2D" parent="Left"] +shape = SubResource( 1 ) + +[node name="Right" type="Area2D" parent="."] +modulate = Color( 1, 0, 1, 1 ) +position = Vector2( 563.815, 188.919 ) +script = ExtResource( 1 ) + +[node name="Sprite" type="Sprite" parent="Right"] +texture = ExtResource( 2 ) + +[node name="Collision" type="CollisionShape2D" parent="Right"] +shape = SubResource( 1 ) + +[node name="Ball" type="Area2D" parent="."] +position = Vector2( 320.5, 191.124 ) +script = ExtResource( 4 ) + +[node name="Sprite" type="Sprite" parent="Ball"] +texture = ExtResource( 5 ) + +[node name="Collision" type="CollisionShape2D" parent="Ball"] +shape = SubResource( 2 ) + +[node name="Separator" type="Sprite" parent="."] +position = Vector2( 320, 200 ) +texture = ExtResource( 6 ) + +[node name="LeftWall" type="Area2D" parent="."] +position = Vector2( -10, 200 ) +script = ExtResource( 7 ) + +[node name="Collision" type="CollisionShape2D" parent="LeftWall"] +shape = SubResource( 3 ) + +[node name="RightWall" type="Area2D" parent="."] +position = Vector2( 650, 200 ) +script = ExtResource( 7 ) + +[node name="Collision" type="CollisionShape2D" parent="RightWall"] +shape = SubResource( 3 ) + +[node name="Ceiling" type="Area2D" parent="."] +position = Vector2( 320, -10 ) +script = ExtResource( 8 ) + +[node name="Collision" type="CollisionShape2D" parent="Ceiling"] +shape = SubResource( 4 ) + +[node name="Floor" type="Area2D" parent="."] +position = Vector2( 320, 410 ) +script = ExtResource( 8 ) +bounce_direction = -1 + +[node name="Collision" type="CollisionShape2D" parent="Floor"] +shape = SubResource( 4 ) + +[node name="Camera2D" type="Camera2D" parent="."] +offset = Vector2( 320, 200 ) +current = true + +[connection signal="area_entered" from="Left" to="Left" method="_on_area_entered"] +[connection signal="area_entered" from="Right" to="Right" method="_on_area_entered"] +[connection signal="area_entered" from="LeftWall" to="LeftWall" method="_on_wall_area_entered"] +[connection signal="area_entered" from="RightWall" to="RightWall" method="_on_wall_area_entered"] +[connection signal="area_entered" from="Ceiling" to="Ceiling" method="_on_area_entered"] +[connection signal="area_entered" from="Floor" to="Floor" method="_on_area_entered"] diff --git a/cpp/pong/project/project.godot b/cpp/pong/project/project.godot new file mode 100644 index 0000000..4fc1d3c --- /dev/null +++ b/cpp/pong/project/project.godot @@ -0,0 +1,72 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=4 + +[application] + +config/name="Pong with GDNative C++" +config/description="A simple Pong game. This demo shows best practices +for game development in Godot, including signals." +run/main_scene="pong.tscn" +config/icon="res://icon.png" + +[display] + +window/size/width=640 +window/size/height=400 +window/dpi/allow_hidpi=true +window/stretch/mode="2d" +window/stretch/aspect="expand" +stretch_2d=true + +[gdnative] + +singletons=[ ] + +[input] + +left_move_down={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":90,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null) + ] +} +left_move_up={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null) + ] +} +right_move_down={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":1,"button_index":13,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":1,"axis_value":1.0,"script":null) + ] +} +right_move_up={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":1,"button_index":12,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":1,"axis_value":-1.0,"script":null) + ] +} + +[rendering] + +quality/driver/driver_name="GLES2" +2d/snapping/use_gpu_pixel_snap=true +vram_compression/import_etc=true +vram_compression/import_etc2=false +quality/2d/use_pixel_snap=true +viewport/default_clear_color=Color( 0, 0, 0, 1 ) diff --git a/cpp/pong/project/separator.png b/cpp/pong/project/separator.png new file mode 100644 index 0000000..30c44fc Binary files /dev/null and b/cpp/pong/project/separator.png differ diff --git a/cpp/pong/project/separator.png.import b/cpp/pong/project/separator.png.import new file mode 100644 index 0000000..a8527c6 --- /dev/null +++ b/cpp/pong/project/separator.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/separator.png-f981c8489b9148e2e1dc63398273da74.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://separator.png" +dest_files=[ "res://.import/separator.png-f981c8489b9148e2e1dc63398273da74.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/cpp/pong/screenshots/pong.png b/cpp/pong/screenshots/pong.png new file mode 100644 index 0000000..2179d65 Binary files /dev/null and b/cpp/pong/screenshots/pong.png differ diff --git a/cpp/pong/src/ball.cpp b/cpp/pong/src/ball.cpp new file mode 100644 index 0000000..1a9ee36 --- /dev/null +++ b/cpp/pong/src/ball.cpp @@ -0,0 +1,24 @@ +#include "ball.hpp" + +void Ball::_ready() { + _initial_pos = get_position(); +} + +void Ball::_process(double p_delta) { + _speed += p_delta * 2; + godot::Vector2 position = get_position(); + position += _speed * p_delta * direction; + set_position(position); +} + +void Ball::reset() { + direction = godot::Vector2(-1, 0); + set_position(_initial_pos); + _speed = DEFAULT_SPEED; +} + +void Ball::_register_methods() { + godot::register_method("_ready", &Ball::_ready); + godot::register_method("_process", &Ball::_process); + godot::register_method("reset", &Ball::reset); +} diff --git a/cpp/pong/src/ball.hpp b/cpp/pong/src/ball.hpp new file mode 100644 index 0000000..c60a585 --- /dev/null +++ b/cpp/pong/src/ball.hpp @@ -0,0 +1,25 @@ +#ifndef BALL_H +#define BALL_H + +#include +#include + +class Ball : public godot::Area2D { + GODOT_CLASS(Ball, godot::Area2D) + + const int DEFAULT_SPEED = 100; + real_t _speed = DEFAULT_SPEED; + godot::Vector2 _initial_pos; + +public: + godot::Vector2 direction = godot::Vector2(-1, 0); + + void _init() {} + void _ready(); + void _process(double p_delta); + void reset(); + + static void _register_methods(); +}; + +#endif // BALL_H diff --git a/cpp/pong/src/ceiling_floor.cpp b/cpp/pong/src/ceiling_floor.cpp new file mode 100644 index 0000000..f7712ff --- /dev/null +++ b/cpp/pong/src/ceiling_floor.cpp @@ -0,0 +1,12 @@ +#include "ceiling_floor.hpp" + +void CeilingFloor::_on_area_entered(Ball *p_ball) { + if (p_ball->get_name() == "Ball") { + p_ball->direction = (p_ball->direction + godot::Vector2(0, bounce_direction)).normalized(); + } +} + +void CeilingFloor::_register_methods() { + godot::register_method("_on_area_entered", &CeilingFloor::_on_area_entered); + godot::register_property("bounce_direction", &CeilingFloor::bounce_direction, 1); +} diff --git a/cpp/pong/src/ceiling_floor.hpp b/cpp/pong/src/ceiling_floor.hpp new file mode 100644 index 0000000..0a7d538 --- /dev/null +++ b/cpp/pong/src/ceiling_floor.hpp @@ -0,0 +1,21 @@ +#ifndef CEILING_FLOOR_H +#define CEILING_FLOOR_H + +#include +#include + +#include "ball.hpp" + +class CeilingFloor : public godot::Area2D { + GODOT_CLASS(CeilingFloor, godot::Area2D) + +public: + int bounce_direction = 1; + + void _init() {} + void _on_area_entered(Ball *p_ball); + + static void _register_methods(); +}; + +#endif // CEILING_FLOOR_H diff --git a/cpp/pong/src/entry.cpp b/cpp/pong/src/entry.cpp new file mode 100644 index 0000000..398d5d0 --- /dev/null +++ b/cpp/pong/src/entry.cpp @@ -0,0 +1,23 @@ +#include + +#include "ball.hpp" +#include "ceiling_floor.hpp" +#include "paddle.hpp" +#include "wall.hpp" + +extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { + godot::Godot::gdnative_init(o); +} + +extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { + godot::Godot::gdnative_terminate(o); +} + +extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) { + godot::Godot::nativescript_init(handle); + + godot::register_class(); + godot::register_class(); + godot::register_class(); + godot::register_class(); +} diff --git a/cpp/pong/src/paddle.cpp b/cpp/pong/src/paddle.cpp new file mode 100644 index 0000000..fdaed7c --- /dev/null +++ b/cpp/pong/src/paddle.cpp @@ -0,0 +1,40 @@ +#include "paddle.hpp" + +#include +#include + +void Paddle::_ready() { + _screen_size_y = get_viewport_rect().size.y; + godot::String n = godot::String(get_name()).to_lower(); + _up = n + "_move_up"; + _down = n + "_move_down"; + if (n == "left") { + _ball_dir = 1; + } else { + _ball_dir = -1; + } +} + +void Paddle::_process(double delta) { + godot::Input *input = godot::Input::get_singleton(); + // Move up and down based on input. + real_t keyboard_input = input->get_action_strength(_down) - input->get_action_strength(_up); + godot::Vector2 position = get_position(); + position.y = godot::Math::clamp(position.y + keyboard_input * MOVE_SPEED * delta, 16.0, _screen_size_y - 16.0); + set_position(position); +} + +void Paddle::_on_area_entered(Ball *p_ball) { + if (p_ball->get_name() == "Ball") { + godot::Ref random = godot::RandomNumberGenerator::_new(); + random->randomize(); + // Assign new direction. + p_ball->direction = godot::Vector2(_ball_dir, random->randf() * 2 - 1).normalized(); + } +} + +void Paddle::_register_methods() { + godot::register_method("_ready", &Paddle::_ready); + godot::register_method("_process", &Paddle::_process); + godot::register_method("_on_area_entered", &Paddle::_on_area_entered); +} diff --git a/cpp/pong/src/paddle.hpp b/cpp/pong/src/paddle.hpp new file mode 100644 index 0000000..678d67a --- /dev/null +++ b/cpp/pong/src/paddle.hpp @@ -0,0 +1,29 @@ +#ifndef PADDLE_H +#define PADDLE_H + +#include +#include + +#include "ball.hpp" + +class Paddle : public godot::Area2D { + GODOT_CLASS(Paddle, godot::Area2D) + + const int MOVE_SPEED = 100; + + int _ball_dir; + godot::String _up; + godot::String _down; + + real_t _screen_size_y; + +public: + void _init() {} + void _ready(); + void _process(double p_delta); + void _on_area_entered(Ball *p_area); + + static void _register_methods(); +}; + +#endif // PADDLE_H diff --git a/cpp/pong/src/wall.cpp b/cpp/pong/src/wall.cpp new file mode 100644 index 0000000..887cd1c --- /dev/null +++ b/cpp/pong/src/wall.cpp @@ -0,0 +1,12 @@ +#include "wall.hpp" + +void Wall::_on_wall_area_entered(Ball *p_ball) { + if (p_ball->get_name() == "Ball") { + // Ball went out of game area, reset. + p_ball->reset(); + } +} + +void Wall::_register_methods() { + godot::register_method("_on_wall_area_entered", &Wall::_on_wall_area_entered); +} diff --git a/cpp/pong/src/wall.hpp b/cpp/pong/src/wall.hpp new file mode 100644 index 0000000..5604ca2 --- /dev/null +++ b/cpp/pong/src/wall.hpp @@ -0,0 +1,19 @@ +#ifndef WALL_H +#define WALL_H + +#include +#include + +#include "ball.hpp" + +class Wall : public godot::Area2D { + GODOT_CLASS(Wall, godot::Area2D) + +public: + void _init() {} + void _on_wall_area_entered(Ball *p_area); + + static void _register_methods(); +}; + +#endif // WALL_H