Qt SFML. Example of connection with local and remote JavaScript server with WebSockets
-
Qt Version: 5.15.2
SFML: 2.5.1Qt SFML Client: https://github.com/8Observer8/NodeJSWebSocketClient_QtSFML_Qt5Cpp
Node.js server: https://github.com/8Observer8/nodejs-websocket-server-jsHello,
It is not a question. It is just a simple example. It will be useful for someone who wants to write a multiplayer games with QtWebSockets and SFML. I found somewhere an example for integration of SFML to Qt Widget. There is a class called "QSfmlWidget". You can copy "QSfmlWidget.h" and "QSfmlWidget.cpp" to your project and inherit from QSfmlWidget your widget. Override to methods in your widget:
onInit()
andonUpdate()
. My example contains a simple server script that you can upload on free Heroku server. The Qt client draws a rectangle using SFML:and makes a connection with Node.js server. The Qt client send the message "Hello, server!". The server send the message "Hello, client!". The server and the client print these messages to the console. The Qt client will print to the console the message:
Connection "{\"msg\":\"Hello, client!\"}" "Hello, client!"
If you need a local server just comment/uncomment the respective line of code:
// QUrl url("ws://localhost:3000"); QUrl url("ws://nodejs-websocket-server-js.herokuapp.com"); m_webSocket.open(url);
Server:
app.js
const express = require("express"); const http = require("http"); const ws = require("ws"); const path = require("path"); const fs = require("fs"); const app = express(); app.use(express.static(path.join(__dirname, "./public"))); app.get("/", (req, res) => { res.sendFile(path.join(__dirname, "index.html")) }); const httpServer = http.createServer(app); const wss = new ws.Server({ server: httpServer }); wss.on("connection", (ws) => { console.log("Client was connected"); ws.send(JSON.stringify({ msg: "Hello, client!" })); ws.onmessage = (event) => { const msg = JSON.parse(event.data); console.log(msg); }; }); const port = process.env.PORT || 3000; httpServer.listen(port, () => { console.log("Server started. Port: ", port); });
It is a web client, just for example:
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Web Client</title> </head> <body> <script> const ws = new WebSocket("ws://localhost:3000"); // const ws = new WebSocket("wss://nodejs-websocket-server-js.herokuapp.com"); ws.onopen = () => { console.log("Connection"); ws.send(JSON.stringify({ msg: "Hello, server!" })); }; ws.onmessage = (event) => { const msg = JSON.parse(event.data); console.log(msg); }; </script> </body> </html>
You need to have these modules:
express
andws
. Do not forget to add"start": "node app.js"
topackage.json
- it is for Heroku.package.json
{ "name": "nodejs-websocket-server-js", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node app.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "ws": "^7.3.1" } }
Qt Client with SFML:
NodeJSWebSocketClient_QtSFML_Qt5Cpp.pro
QT += core gui websockets INCLUDEPATH += "E:\Libs\SFML-2.5.1-mingw-32bit\include" LIBS += -L"E:\Libs\SFML-2.5.1-mingw-32bit\lib" LIBS += -lsfml-system -lsfml-graphics -lsfml-window greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ QSfmlWidget.cpp \ main.cpp \ MainWindow.cpp HEADERS += \ MainWindow.h \ QSfmlWidget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QtWebSockets/QWebSocket> #include "QSfmlWidget.h" class MainWindow : public QSfmlWidget { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); void onInit() override; void onUpdate() override; private slots: void onConnected(); void onMessageReceived(const QString &message); private: sf::RectangleShape m_rect; QWebSocket m_webSocket; }; #endif // MAINWINDOW_H
MainWindow.cpp
#include <QtCore/QJsonDocument> #include <QtCore/QJsonObject> #include "MainWindow.h" MainWindow::MainWindow(QWidget *parent) : QSfmlWidget(parent) { setWindowTitle("Qt SFML WebSocket Client"); setFixedSize(QSize(350, 350)); connect(&m_webSocket, &QWebSocket::connected, this, &MainWindow::onConnected); connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &MainWindow::onMessageReceived); QUrl url("ws://localhost:3000"); // QUrl url("ws://nodejs-websocket-server-js.herokuapp.com"); m_webSocket.open(url); } void MainWindow::onInit() { m_rect.setPosition(50, 100); m_rect.setSize(sf::Vector2f(100, 50)); m_rect.setFillColor(sf::Color::Green); } void MainWindow::onUpdate() { sf::RenderWindow::draw(m_rect); } void MainWindow::onConnected() { qDebug() << "Connection"; // Send a message to a server QJsonObject jsonObject; jsonObject["msg"] = "Hello, server!"; QJsonDocument doc(jsonObject); QString strJson(doc.toJson(QJsonDocument::Compact)); m_webSocket.sendTextMessage(strJson); } void MainWindow::onMessageReceived(const QString &message) { qDebug() << message; // Output: "{\"msg\":\"Hello, client!\"}" QJsonDocument doc(QJsonDocument::fromJson(message.toUtf8())); QJsonObject data = doc.object(); qDebug() << data["msg"].toString(); // Output: "Hello, client!" }
QSfmlWidget.h
#ifndef QSFMLWIDGET_H #define QSFMLWIDGET_H #include <QObject> #include <QTimer> #include <QWidget> #include <SFML/Graphics.hpp> class QSfmlWidget : public QWidget, public sf::RenderWindow { Q_OBJECT public: explicit QSfmlWidget(QWidget *parent = nullptr); virtual QPaintEngine * paintEngine() const override; virtual void showEvent(QShowEvent *event) override; virtual void paintEvent(QPaintEvent *event) override; virtual void onInit(); virtual void onUpdate(); private: QTimer m_timer; bool m_initialized; }; #endif // QSFMLWIDGET_H
QSfmlWidget.cpp
#include "QSfmlWidget.h" QSfmlWidget::QSfmlWidget(QWidget *parent) : QWidget(parent) , m_initialized(false) { setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_NoSystemBackground); setFocusPolicy(Qt::StrongFocus); } QPaintEngine *QSfmlWidget::paintEngine() const { return nullptr; } void QSfmlWidget::showEvent(QShowEvent *event) { Q_UNUSED(event); if (!m_initialized) { sf::RenderWindow::create(reinterpret_cast<sf::WindowHandle>(winId())); onInit(); connect(&m_timer, SIGNAL(timeout()), this, SLOT(repaint())); m_timer.start(); m_initialized = true; } } void QSfmlWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); RenderWindow::clear(sf::Color::White); onUpdate(); RenderWindow::display(); } void QSfmlWidget::onInit() { // To be overriden } void QSfmlWidget::onUpdate() { // To be overriden }
main.cpp
#include "MainWindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }