Search code examples
c++wxwidgets

Class variable gets updated only once in gameloop


I have a problem with updating the value of a class variable on each frame of gameloop.

I am using wxWidgets for creating a cross-platform window and for graphics as well as gameloop. This is my main Window class which implements rendering and the gameloop.

#include <wx/wx.h>
#include "window.h"
#include "../entity/entity.h"
#include "../../configuration.h"

Window::Window(const wxString & title, const wxPoint & position, const wxSize & size): wxFrame(nullptr, wxID_ANY, title, position, size) {
    timer = new wxTimer(this, 1);

    Entity entity((width / 2) - 50, 100, 100, 100, wxColour(255, 0, 0));
    AddEntity(entity);

    Connect(wxEVT_PAINT, wxPaintEventHandler(Window::OnPaint));
    Connect(wxEVT_TIMER, wxCommandEventHandler(Window::OnTimer));

    Start();
}

void Window::Render(wxPaintEvent & event) {
    wxPaintDC dc(this);

    for (Entity entity : entities) {
        entity.Render(dc);
    }
}

void Window::Update(wxCommandEvent & event) {
    for (Entity entity : entities) {
        entity.Update();
    }
}

void Window::AddEntity(Entity & entity) {
    entities.push_back(entity);
}

void Window::OnTimer(wxCommandEvent & event) {
    Update(event);
}

void Window::OnPaint(wxPaintEvent & event) {
    Render(event);
}

void Window::Start() {
    isStarted = true;
    timer->Start(10);
}

void Window::Stop() {
    isPaused = !isPaused;

    if (isPaused) {
        timer->Stop();
    } else {
        timer->Start(10);
    }
}

Here is the Entity class which represent a rectangle that can be drawn onto the window.

#include <wx/wx.h>
#include <stdlib.h>
#include "entity.h"
#include "../gravity/gravity.h"

Entity::Entity(int _x, int _y, int _width, int _height, wxColour _color) : x( _x ), y( _y ), width( _width ), height( _height ), color( _color ) {
    
}

void Entity::Render(wxPaintDC & dc) {
    wxPen pen(color);
    dc.SetPen(pen);

    dc.DrawLine(x, y, x + width, y);
    dc.DrawLine(x, y + height, x + width, y + height);
    dc.DrawLine(x, y, x, y + height);
    dc.DrawLine(x + width, y, x + width, y + height);
}

void Entity::Update() {
    y += 1;
    std::cout << y << std::endl;
}

On each call of the Entity::Update() method, I want to increment the y position and rerender the entity. However, the value of y gets incremented only once and stays the same for the rest of the application lifetime and I can't seem to understand why. I'll be thankful for any help.


Solution

  • When you loop over your entities like this (in Window::Render, Window::Update):

    for (Entity entity : entities) {
    

    in each iteration entity will get a copy of the element in entities.

    In order to operate on your actual entities via a reference you need to change it to:

    //----------v---------------------
    for (Entity & entity : entities) {
    

    Another option is to use auto & (auto by itself does not include "reference-ness" and so will force again a copy as in your code):

    //---vvvvvv---------------------
    for (auto & entity : entities) {
    

    Note that even if you only read data from your elements (and don't modify it) you can change your loop to use const & to save the copies.