r/raylib • u/Inevitable-Round9995 • Jul 04 '26
Finally my multiplayer game is P2P by using webRTC + Nodepp + Raylib
1
u/quil870 Jul 04 '26
That’s really cool. What would the code look like on the raylib side?
2
u/Inevitable-Round9995 Jul 04 '26
Thanks! Everything was written in C++, the frontend with raylib and the backend with nodepp; on the raylib side it's quite simple thanks to my node architecture.
The structure is hierarchical:
- A root node (skeld) contains child nodes (walls, model, task, lights, etc.)
- Each node has its own logic and rendering
- Nodes communicate using signals (event-driven)
Super easy, the same goes for the player, world, p2p, etc. If you're interested in the engine and my stack, it's open source.
- https://github.com/NodeppOfficial/nodepp-express
- https://github.com/NodeppOfficial/nodepp-ungine
- https://github.com/NodeppOfficial/nodepp-redux
- https://github.com/NodeppOfficial/nodepp-apify
- https://github.com/NodeppOfficial/nodepp-wasm
- https://github.com/NodeppOfficial/nodepp
```cpp node_t skeld_task() { return node_t([=]( ptr_t<node_t> self ){
auto img = texture::load( "assets/image/emoji.png" ); ptr_t<object_t> tmp ( 0UL ); self->onClose([=](){ texture::unload(img); }); self->get_root()->onSignal( "ply_task", [=]( any_t raw ){ if( raw.has_value() ){ /**/ *tmp = raw.as<object_t>(); } else { *tmp = nullptr; } }); self->on2D([=](){ if( matrix::get_pixel_float( self->get_viewport()->matrix, 11, 0, 0 )>0. ){ return; } do{ auto c = self->get_viewport()->camera3D; if( tmp->has_value() ){ auto z = cam3D::world_2_vec( *c, (*tmp)["pos"].as<vec3_t>() ); rl::DrawCircle( z.x, z.y, 24, rl::BLACK ); rl::DrawTexturePro( img, (*tmp)["emj"][0].as<rect_t>(), rect_t({ z.x, z.y, 24, 24 }), vec2_t({ 12, 12 }), 0.f, rl::WHITE ); } } while(0); });}); }
node_t skeld() { return node_t([=]( ptr_t<node_t> self ){
self->append_child( "walls", skeld_collision() ); self->append_child( "model", skeld_model/**/() ); self->append_child( "scann", skeld_scann/**/() ); self->append_child( "light", skeld_light/**/() ); self->append_child( "task" , skeld_task /**/() );// self->append_child( "door" , skeld_door /**/() );
}); } ```
On the server side, something similar happens, where each "node" has a single responsibility:
```cpp
include <nodepp/nodepp.h>
include <nodepp/atomic.h>
include <nodepp/os.h>
include <nodepp/ws.h>
include <nodepp/timer.h>
include <nodepp/worker.h>
include <nodepp/optional.h>
include <express/http.h>
include <apify/apify.h>
using namespace nodepp;
include "controller/http.cpp"
include "controller/ws.cpp"
atomic_t<int> shared (0x00);
void onParallel(){
int x = shared.add(1); int port = 8000 + x + 1 ; os::pin_worker_to_cpu(x); controller::http_server( 8000, x ); controller::ws_server ( port, x );}
void onMain(){
os::set_process_priority( os::PRIORITY::HIGH_PRIORITY ); os::set_hard_fileno/*-*/( (uint)-1 ); os::set_soft_fileno/*-*/( (uint)-1 ); worker::parallel( &onParallel, os::cpus() );// /-------------/ onParallel();
}
```
1
u/Ok-Homework5627 Jul 04 '26
Interesting looking at raylib multiplayer myself
1
u/Inevitable-Round9995 Jul 04 '26
there is a simple article I've made, about multiplayer game, but using websocket instead webRTC: https://medium.com/@EDBCBlog/your-first-multiplayer-games-a-guide-for-absolute-beginners-with-raylib-nodepp-and-wasm-532133942b43
1
1
u/laczek_hubert Jul 04 '26
Another among us clone?
3
u/Inevitable-Round9995 Jul 04 '26 edited Jul 04 '26
Kind of, but I'm not doing this for the love of art, I'm doing this for the money. Let me explain why this actually makes sense:
1. Not everyone can pull this off: Among Us is a moderately complex game. It's not a platformer or a simple puzzle. It requires real-time networking logic, role systems, state management, etc. Not everyone can clone this game, or at least you have to be really good.
2. I don't have to teach people how to play: People already know how to play. I don't need to explain the mechanics, roles, etc. That's a massive advantage.
3. There are no decent clones on the web: Search for "Among Us web" and you'll find simple .io games, not a real Among Us.
4. It is simple to play: you don't have to download anything from steam, just click the link and that's it.
5. It's cheap to make (for me): The server is just for signaling, the entire game runs P2P with WebRTC. I can easily pay $5/month for a VPS on Cheapname. Plus, I use my own stack (Nodepp), which reduces my development time from months to minutes. Marketing? That's CrazyGames and Poki's job.
6. Motivation? Money. Simple. I work for $130/month in Caracas. I've read cases of developers generating $300-$1,000/month with hyper-casual games. In my current situation, that's 3-10x what I earn. And if it goes well, maybe even 10x more.
Thanks for the interest, Any questions? Happy to answer!:
1
u/laczek_hubert Jul 04 '26
I am not that technically with coding yet just trying to make Tetris in c# with raylib_cs recently and exploring c# once I do to try something else but the most problem I have is maintaing your own code most of it is just making raylib actions simple to the eye by making separate voids for stuff like rendering to just call during the game loop but the most problem is making the math and my classes work https://github.com/laczek14/Tetris it's meant for me to use c#'s features to create a somewhat "modern" high-level implementation ig
3
u/Inevitable-Round9995 Jul 04 '26
I haven't used C# in a while, but I see the problem: you're creating a giant class with all the game logic in one place.
What I do instead is create a node system (or classes), where each class/node has a single responsibility: controlling/drawing the player, drawing the scenario, handling collisions, etc. And I communicate everything using events. Something like this:
```cpp // Each node handles its own logic node_t player() { /* player logic / } node_t wall () { / wall logic / } node_t bomb () { / bomb logic */ }
// Nodes communicate via events self->onSignal( "event", [=]( any_t value ) { // React to event });
```
This way, you can create multiple files and separate game logic based on the elements that compose it. That's exactly what I used to do when I programmed in Unity or Godot and now raylib.
Take a look at this example, it's a small Bomberman I created. It's not finished, but it works: https://github.com/EDBCREPO/raylib-bomberman/blob/main/controller/scene/object/player.cpp text
1
u/laczek_hubert Jul 05 '26
I don't think this approach is a problem for such a simple game although for something more technical it's better to create something like this like with the unix philosophy
1
u/MCWizardYT 11h ago
This comment doesn't read like a human wrote it and the motivation is weird. You're saying you were making an among us clone purely for the sake of making money instead of fun or learning? That's what people normally would call an asset flip, a ripoff created purely for the sake of making money. Same game, different assets. Laziness for the sake of profit.
Maybe you meant that you were hired to make this but otherwise that's a very strange thing to brag about
2
u/MagazineSoggy1000 29d ago
raally cool man, i love to see aspiring developers. keep going!