Skip to content
Snippets Groups Projects
Commit d5e99254 authored by Armin Co's avatar Armin Co
Browse files

Playable.

parent 29834bc2
No related branches found
No related tags found
No related merge requests found
# QPong – Quanten-Pong
#### This is the new pong ;)
#### This is the new pong ;)e
---
Controls for Player one: a & q and for Player two ö & ü.
---
Dependencies:
* cmake
* libgtkmm-3.0-dev
* libfftw3-dev
---
### Build and run
````
mkdir build && cd build
......@@ -21,3 +24,8 @@ make
./src/qpong.app
````
## Erweiterungsideen
- Konfiguration über die GUI, evt. mit speichern
- Spalt & Interferen
- Controller-Schnittstelle (für z.B. Mikrofon, Joysticks oder Potis)
\ No newline at end of file
......@@ -9,8 +9,8 @@
namespace QPong
{
constexpr int arrayWidth = 284;
constexpr int arrayHeight = 284;
constexpr int arrayWidth = 256;
constexpr int arrayHeight = 256;
constexpr unsigned arraySize = arrayWidth * arrayHeight;
......
......@@ -15,7 +15,7 @@
/// @brief Planck constant.
///
constexpr double hbar = 0.0001;
constexpr double hbar = 0.0002;
const std::complex<double> Ci(0.0, 1.0);
......@@ -57,7 +57,7 @@ const double obstaclePotential(double x, double y, double x0, double y0)
{
y -= y0;
constexpr double vx = 100000.0;
constexpr double vx = 100000.0 / 2.0;
double E = 0.0;
constexpr double height = 0.31;
......@@ -81,7 +81,6 @@ const double obstaclePotential(double x, double y, double x0, double y0)
double d = x0-x;
E = 1.0 / (d * vx);
}
return E;
}
......@@ -98,32 +97,41 @@ void Particle::initMomentum()
double x = xAt(ix);
unsigned index = QPong::arrayWidth * iy + ix;
constexpr double k_px0 = 0.025;
constexpr double k_py0 = 0.009;
constexpr double k_px0 = 0.075;
constexpr double k_py0 = 0.052;
constexpr double k_x0 = 0.0;
constexpr double k_y0 = -0.0;
constexpr double lambda = 70.0;
constexpr double A0 = 2.5;
constexpr double A0 = 0.9;
m_psi[index] = A0 * exp(Ci / hbar * (x * k_px0 + y * k_py0) - lambda * (sqr(x - k_x0) + sqr(y - k_y0)));
sumAtInit += sqr(real(m_psi[index])) + sqr(imag(m_psi[index]));
}
}
for (auto p : m_players)
{
m_players[p.first].score = 0;
}
std::cout << sumAtInit << std::endl;//" " << m_players[Player::One].score << " " << m_players[Player::Two].score << std::endl;
for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
{
double y = yAt(iy);
for (unsigned ix = 0; ix < QPong::arrayWidth; ix++)
{
double x = xAt(ix);
unsigned index = QPong::arrayWidth * iy + ix;
m_psi[index] *= 1.0 / sqrt(sumAtInit);
}
}
std::cout << sumAtInit << std::endl;
}
constexpr double playerOneStartX = -0.7;
constexpr double playerTwoStartX = 0.7;
Particle::Particle(ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles)
Particle::Particle(ParticleImage *momentum, ParticleImage *position)
: m_bufMomentumRepresentation{momentum}
, m_bufPositionRepresentation{position}
, m_obstacleImage{obstacles}
, m_ready{false}
{
m_players.insert(std::make_pair(Player::One, PlayerData {playerOneStartX, 0.0}));
......@@ -158,49 +166,50 @@ bool Particle::notReady()
void Particle::propagate()
{
updatePlayers();
constexpr double dt = 0.1;
constexpr double dt = 0.05;
sumAtInit = 0;
#pragma omp parallel for
// #pragma omp parallel for
for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
{
double y = yAt(iy);
#pragma omp parallel for
// #pragma omp parallel for
for (unsigned long ix = 0; ix < QPong::arrayWidth; ix++)
{
double x = xAt(ix);
int index = QPong::arrayWidth * iy + ix;
sumAtInit += sqr(real(m_psi[index])) + sqr(imag(m_psi[index]));
// destroy ^^
if (x < playerOneStartX) //< expexts p1.x < 0
{
double cx = -playerOneStartX + x;
cx = cx * (M_PI / 2) / (1.0 - playerOneStartX);
cx = cx * (M_PI / 2) / (1.0 + playerOneStartX);
double e = cos(cx) * cos(cx);
std::complex<double> tmp = m_psi[index];
double normPre = sqr(std::real(m_psi[index])) + sqr(std::real(m_psi[index]));
m_psi[index] *= e;
tmp -= m_psi[index];
m_players[Player::Two].score += sqr(real(tmp)) + sqr(imag(tmp));
double dif = normPre - (sqr(std::real(m_psi[index])) + sqr(std::real(m_psi[index])));
m_players[Player::Two].score += dif;
}
if (x > playerTwoStartX) //< expects p2.x > 0
{
double cx = x - playerTwoStartX;
cx = cx * (M_PI / 2) / (1.0 - playerOneStartX);
cx = cx * (M_PI / 2) / (1.0 - playerTwoStartX);
double e = cos(cx) * cos(cx);
std::complex<double> tmp = m_psi[index];
double normPre = sqr(std::real(m_psi[index])) + sqr(std::real(m_psi[index]));
m_psi[index] *= e;
tmp -= m_psi[index];
m_players[Player::One].score += sqr(std::real(tmp)) + sqr(std::imag(tmp));
double dif = normPre - (sqr(std::real(m_psi[index])) + sqr(std::real(m_psi[index])));
m_players[Player::One].score += dif;
}
// obstacles
double E = obstaclePotential(x, y, m_players[Player::One].x, m_players[Player::One].y);
double E2 = obstaclePotential(x, y, m_players[Player::Two].x, m_players[Player::Two].y);
double E3 = sqr(y) * sqr(y) * sqr(y) * 0.001;
double E3 = sqr(y) * sqr(y) * sqr(y) * sqr(y) * 0.002;
std::complex<double> tmp = m_psi[index] * exp(-Ci * dt / hbar * (E + E2 + E3));
m_psi[index] = tmp;
m_bufPositionRepresentation->updateBuffer(index, tmp, (E+E2+E3*0.99)*800);
m_bufPositionRepresentation->updateBuffer(index, tmp * 95.0, (E+E2+E3*0.8)*600);
}
}
......@@ -256,7 +265,7 @@ void Particle::updateMomentumImage()
px = x + QPong::arrayWidth / 2;
}
constexpr double scale = 164.0;
constexpr double scale = 164.0 * 95.0;
array_index = y * QPong::arrayWidth + x;
momentum_index = py * QPong::arrayWidth + px;
m_bufMomentumRepresentation->updateBuffer(array_index, (m_psi[momentum_index] * scale), 0.0);
......@@ -268,7 +277,7 @@ constexpr double speedStepSize = 0.0005;
void Particle::updateObstacle(Player player, Move direction)
{
constexpr double addSpped = 17;
constexpr double addSpped = 3;
switch (direction)
{
case Move::Up:
......@@ -279,7 +288,7 @@ void Particle::updateObstacle(Player player, Move direction)
break;
}
constexpr double maxSpeedScale = 42;
constexpr double maxSpeedScale = 33;
if (m_players[player].vy > speedStepSize * maxSpeedScale)
{
m_players[player].vy = speedStepSize * maxSpeedScale;
......@@ -311,7 +320,7 @@ void Particle::updatePlayers()
m_players[p.first].vy = 0.0;
}
constexpr double maxY = 1;
constexpr double maxY = 1.3;
if (m_players[p.first].y > maxY)
{
m_players[p.first].y = maxY;
......
......@@ -41,7 +41,7 @@ class Particle
{
public:
Particle() = delete;
Particle(ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles);
Particle(ParticleImage *momentum, ParticleImage *position);
~Particle();
/// @brief Execute one step of the simulation.
......@@ -77,7 +77,6 @@ private:
ParticleImage *m_bufPositionRepresentation;
ParticleImage *m_bufMomentumRepresentation;
ParticleImage *m_obstacleImage;
/// @brief Update the array at the ArrayCanvas
///
......
......@@ -12,7 +12,7 @@ QDrawingArea::QDrawingArea()
m_dispatcher.connect(sigc::mem_fun(*this, &QDrawingArea::queue_draw));
}
void QDrawingArea::triggerRedraw()
void QDrawingArea::redraw()
{
m_dispatcher.emit();
}
......@@ -20,7 +20,6 @@ void QDrawingArea::triggerRedraw()
void QDrawingArea::setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
{
// if ((pixbuf != nullptr) && (m_image != nullptr))
m_image = pixbuf;
}
......
......@@ -15,7 +15,7 @@ public:
QDrawingArea();
virtual ~QDrawingArea(){};
void triggerRedraw();
void redraw();
void setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
protected:
......
#include <iostream>
#include <iomanip>
#include <chrono>
#include "QWindow.hpp"
......@@ -7,6 +8,11 @@ bool propagating = true;
int propRate = 0;
int renderRate = 0;
bool qPressed = false;
bool aPressed = false;
bool upPressed = false;
bool downPressed = false;
/// @brief This functino has to run in its own thread and propagates the particle as fast as possible.
///
void simulation(Particle *p)
......@@ -16,6 +22,26 @@ void simulation(Particle *p)
auto start = std::chrono::system_clock::now();
p->propagate();
propRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
if (qPressed)
p->updateObstacle(Player::One, Move::Up);
if (aPressed)
p->updateObstacle(Player::One, Move::Down);
if (upPressed)
p->updateObstacle(Player::Two, Move::Up);
if (downPressed)
p->updateObstacle(Player::Two, Move::Down);
// Sync propagating with drawing if prop is faster.
auto dt = std::chrono::system_clock::now() - start;
constexpr int propTime = 150;
if (dt.count() < propTime)
{
std::this_thread::sleep_for(std::chrono::milliseconds(propTime - dt.count()));
}
}
while (propagating);
}
......@@ -29,7 +55,7 @@ void render(QWindow *w)
using namespace std::chrono_literals;
auto start = std::chrono::system_clock::now();
std::this_thread::sleep_for(20ms);
w->emitImageDraw();
w->updateView();
renderRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
} while (true);
}
......@@ -40,11 +66,11 @@ QWindow::QWindow()
, m_scorePlayerOne("0")
, m_scorePlayerTwo("0")
{
set_border_width(10);
set_border_width(5);
m_momentum = new ParticleImage;
m_position = new ParticleImage;
m_particle = new Particle(m_momentum, m_position, m_obstacle);
m_particle = new Particle(m_momentum, m_position);
add(m_box);
m_box.pack_start(m_vBox);
......@@ -59,7 +85,7 @@ QWindow::QWindow()
m_scoreBox.pack_start(m_scorePlayerTwo, Gtk::PACK_EXPAND_WIDGET);
m_vBox.pack_start(m_scoreBox, Gtk::PACK_SHRINK);
m_hBox.pack_start(m_positionArea);
m_hBox.pack_start(m_positionArea, Gtk::PACK_EXPAND_WIDGET);
m_hBox.pack_start(m_momentumArea, Gtk::PACK_EXPAND_WIDGET);
m_vBox.pack_start(m_hBox);
......@@ -75,6 +101,7 @@ QWindow::QWindow()
m_button.signal_clicked().connect(sigc::mem_fun(*this, &QWindow::onButtonPress));
this->signal_key_press_event().connect( sigc::mem_fun( *this, &QWindow::onKeyPress));
this->signal_key_release_event().connect(sigc::mem_fun(*this, &QWindow::onKeyPress));
m_guiDispatcher.connect(sigc::mem_fun(*this, &QWindow::updateGui));
m_areaDispatcher.connect(sigc::mem_fun(*this, &QWindow::updateImage));
......@@ -111,12 +138,24 @@ void QWindow::updateGui()
ss = std::stringstream();
ss << "Score Player 1: ";
ss << m_particle->getScore(Player::One);
double score = m_particle->getScore(Player::One) * 100;
ss << std::setprecision(2) << std::setw(7) << score << " %";
if (score > 50.0)
{
ss << std::endl << "GEWONNEN!";
ss << std::endl << "Zum Neustarten Partikel neu initialisieren";
}
m_scorePlayerOne.set_text(ss.str());
ss = std::stringstream();
ss << "Score Player 2: ";
ss << m_particle->getScore(Player::Two);
score = m_particle->getScore(Player::Two) * 100;
ss << std::setprecision(2) << std::setw(7) << score << " %";
if (score > 50.0)
{
ss << std::endl << "GEWONNEN!";
ss << std::endl << "Zum Neustarten Partikel neu initialisieren";
}
m_scorePlayerTwo.set_text(ss.str());
}
}
......@@ -125,29 +164,37 @@ void QWindow::updateGui()
bool QWindow::onKeyPress(GdkEventKey* event)
{
constexpr int q = 113;
if (event->keyval == q)
{
m_particle->updateObstacle(Player::One, Move::Up);
}
constexpr int a = 97;
if (event->keyval == a)
{
m_particle->updateObstacle(Player::One, Move::Down);
}
constexpr int ue = 252;
if (event->keyval == ue)
{
m_particle->updateObstacle(Player::Two, Move::Up);
}
constexpr int oe = 246;
if (event->type == GdkEventType::GDK_KEY_PRESS)
{
if (event->keyval == q)
qPressed = true;
if (event->keyval == a)
aPressed = true;
if (event->keyval == ue)
upPressed = true;
if (event->keyval == oe)
downPressed = true;
}
if (event->type == GdkEventType::GDK_KEY_RELEASE)
{
m_particle->updateObstacle(Player::Two, Move::Down);
if (event->keyval == q)
qPressed = false;
if (event->keyval == a)
aPressed = false;
if (event->keyval == ue)
upPressed = false;
if (event->keyval == oe)
downPressed = false;
}
return true;
}
void QWindow::emitImageDraw()
void QWindow::updateView()
{
m_areaDispatcher.emit();
m_guiDispatcher.emit();
......@@ -157,8 +204,8 @@ void QWindow::updateImage()
{
m_positionArea.setPixbuf(m_position->getPixbuf());
m_momentumArea.setPixbuf(m_momentum->getPixbuf());
m_positionArea.triggerRedraw();
m_momentumArea.triggerRedraw();
m_positionArea.redraw();
m_momentumArea.redraw();
}
void QWindow::onButtonPress()
......
......@@ -18,12 +18,18 @@
class QWindow : public Gtk::Window
{
public:
/// @brief Constructor of the window
///
QWindow();
/// @brief Virtual destructor of the window.
///
virtual ~QWindow(){}
void updateImage();
void updateGui();
void emitImageDraw();
/// @brief Sends a signal to GTK to redraw
void updateView();
protected:
/// @brief signal handlers
......@@ -32,6 +38,14 @@ protected:
bool onKeyPress(GdkEventKey* event);
private:
/// @brief Updates the QDrawingArea for position and momentum.
///
void updateImage();
/// @brief Update all labels from the gui.
///
void updateGui();
Gtk::Box m_box;
Gtk::VBox m_vBox;
Gtk::HBox m_hBox;
......
......@@ -15,12 +15,11 @@
///
int main(int argc, char* argv[])
{
std::cout << "QPong -- Starting" << std::endl;
std::cout << "QPong -- starting" << std::endl;
auto app = Gtk::Application::create(argc, argv, "de.armin-co.qpong");
QWindow window;
window.set_default_size(1920, 1200);
std::cout << "QPong -- Window created!" << std::endl;
window.set_default_size(1920, 1080);
return app->run(window);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment