Custom QGraphicsItemGroup: boundingRect is not drawn properly - c++

I have a custom QGraphicsItemGroup, with fixed set of children items. I need to make it resizable(already done), but, while resizing, boundingRect is not updating -- though, all child items are drawn correctly. I've tried adding prepareGeometryChange() and update() in different places of the program, but that hasn't helped.
Even this implementation returns default boundingRect:
QRectF FigureGraphicsItemGroup::boundingRect() const
{
return childrenBoundingRect().adjusted(0, 0, 50, 0);
}
And some necessary code(NB no custom painting):
m_right: right control for resize.
QRectF FigureGraphicsItemGroup::boundingRect() const
{
return childrenBoundingRect();
}
void FigureGraphicsItemGroup::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
QPointF pos = event->pos();
if (m_right->contains(pos) && m_right->isVisible())
{
m_isResized = true;
}
else
QGraphicsItemGroup::mousePressEvent(event);
}
void FigureGraphicsItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF pos = event->pos();
if (m_isResized)
{
if (m_previous.x() == -1 && m_previous.y() == -1)
m_previous = pos;
m_delta = pos.x() - m_previous.x();
m_previous = pos;
QGraphicsItem::prepareGeometryChange();
recalculatePositions();
}
else
{
QGraphicsItemGroup::mouseMoveEvent(event);
}
}
void FigureGraphicsItemGroup::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
QPointF pos = event->pos();
if (m_right->contains(pos) && m_right->isVisible())
{
setCursor(Qt::SizeHorCursor);
}
else
{
setCursor(Qt::ArrowCursor);
QGraphicsItemGroup::hoverMoveEvent(event);
}
}
void FigureGraphicsItemGroup::reset()
{
m_isResized = false;
m_delta = 0;
m_previous = QPointF(-1 , -1);
}
void FigureGraphicsItemGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
reset();
QGraphicsItemGroup::mouseReleaseEvent(event);
}
QVariant FigureGraphicsItemGroup::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change)
{
case ItemSelectedHasChanged:
m_isSelected = isSelected();
m_right->setVisible(m_isSelected);
break;
}
return QGraphicsItem::itemChange(change, value);
}
void FigureGraphicsItemGroup::recalculatePositions()
{
int sumX = 1;
QFontMetrics fm(m_zoneNumberSimpleTextItem->font());
m_routeNumberSimpleTextItem->setPos(sumX, m_middle - fm.height());
sumX += m_routeNumberSimpleTextItem->boundingRect().width() * SPACING;
//-------------------------------------------------------------------------------------------
int diameter = fm.height() * SPACING;
int pixLength = fm.width(m_zoneNumberSimpleTextItem->text());
if (pixLength > diameter)
diameter = pixLength;
QPen pen(Qt::red);
pen.setWidth(1);
m_zoneCircleEllipseItem->setRect(sumX, m_middle - diameter, diameter, diameter);
m_zoneCircleEllipseItem->setPen(pen);
m_zoneNumberSimpleTextItem->setPos(sumX + fm.width(m_zoneNumberSimpleTextItem->text()) / 2,
m_middle - fm.height());
sumX += m_zoneCircleEllipseItem->boundingRect().width() * SPACING;
//-------------------------------------------------------------------------------------------
m_fuelSimpleTextItem->setPos(sumX, m_middle * 1.1);
//-------------------------------------------------------------------------------------------
m_leftCornerSvgItem->setPos(sumX, m_middle - m_leftCornerSvgItem->boundingRect().height() / 4);
sumX += m_leftCornerSvgItem->boundingRect().width() * m_scale;
//-------------------------------------------------------------------------------------------
pen.setColor(m_blue);
pen.setWidth(4);
m_leftLineItem->setPen(pen);
int length = m_leftLineItem->line().length() + m_delta / 2;
length = length < 0 ? 0 : length;
m_leftLineItem->setLine(sumX, m_middle, sumX + length, m_middle);
sumX += m_leftLineItem->boundingRect().width();
//-------------------------------------------------------------------------------------------
m_exerciseSvgItem->setPos(sumX - 2, m_middle - m_exerciseSvgItem->boundingRect().height() / 4);
sumX += m_exerciseSvgItem->boundingRect().width() * m_scale;
//-------------------------------------------------------------------------------------------
pen.setColor(m_blue);
pen.setWidth(4);
m_rightLineItem->setPen(pen);
length = m_rightLineItem->line().length() + m_delta / 2;
length = length < 0 ? 0 : length;
m_rightLineItem->setLine(sumX , m_middle, sumX + length, m_middle);
sumX += m_rightLineItem->boundingRect().width();
//-------------------------------------------------------------------------------------------
m_rightCornerSvgItem->setPos(sumX - 2, m_middle - m_rightCornerSvgItem->boundingRect().height() / 4);
sumX += m_rightCornerSvgItem->boundingRect().width() * m_scale;
//-------------------------------------------------------------------------------------------
m_right->setRect(sumX, m_middle, 4, 4);
//-------------------------------------------------------------------------------------------
}
UPD
A little hack helped me: just add removeFromGroup & addToGroup of some item during resize -- and boundingRect will be drawn correctly. But it looks a little bit strange.

Related

Problem with resizing (FormBorderStyle = None)

I got a problem. When I set FormBorderStyle to None to make the form stripped down, it loses its expandability. I need to make it so that I can drag the edge of the form and it expands. That is, return the ability to resizing. How I can make it?
I tried to google it but found solutions for C# and I need to do it in C++
Redrawing WinForm can meet your needs.
You need to set FormBorderStyle to None then use following code.
public:
MyForm(void)
{
InitializeComponent();
this->DoubleBuffered = true;
this->SetStyle(
System::Windows::Forms::ControlStyles::ResizeRedraw,
true);
//
//TODO: Add the constructor code here
//
}
int cGrip = 16; // Grip size
int cCaption = 32;
protected:
virtual void WndProc(System::Windows::Forms::Message %
m) override {
if (m.Msg == 0x84) { // Trap WM_NCHITTEST
Point pos = Point(m.LParam.ToInt32());
pos = this->PointToClient(pos);
if (pos.Y < cCaption) {
m.Result = (IntPtr)2; // HTCAPTION
return;
}
if (pos.X >= this->ClientSize.Width - cGrip &&
pos.Y >= this->ClientSize.Height - cGrip) {
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
if (pos.X <= this->ClientSize.Width - cGrip &&
pos.Y >= this->ClientSize.Height - cGrip) {
m.Result = (IntPtr)16;
return;
}
if (pos.X <= this->ClientSize.Width - cGrip &&
pos.Y <= this->ClientSize.Height - cGrip) {
m.Result = (IntPtr)13;
return;
}
if (pos.X >= this->ClientSize.Width - cGrip &&
pos.Y <= this->ClientSize.Height - cGrip) {
m.Result = (IntPtr)14;
return;
}
}
__super::WndProc(m);
}

SFML: Exception thrown at 0x7767FF05 (ntdll.dll) in Demo.exe: 0xC0000005: Access violation writing location 0x00000004

I got a code on github. After I debug it, it gives me an error as shown belowI got a code on github. After I debug it, it gives me an error as shown: Exception thrown at 0x7767FF05 (ntdll.dll) in Demo.exe: 0xC0000005: Access violation writing location 0x00000004.
[img]https://i.imgur.com/y8QG7vk.png[/img]
Here is my code:
#include <iostream>
#include <math.h>
#include <algorithm>
#include <SFML/Graphics.hpp>
#define SFML_NO_DEPRECATED_WARNINGS
#pragma warning(suppress : 4996)
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
using namespace sf;
const int window_w = 1920;
const int window_h = 1080;
float wid = 1920;
int hei = 1080;
float wid_n = 1920;
float hei_n = 1080;
const int l_size = 80;
const int r_size = 30;
const int h_size = 100;
float speed = 50;
float del = 0;
const int scale = 1;
RenderWindow window(VideoMode(window_w, window_h), "AVL Tree");
Font font;
View view;
struct Node {
int c;
Node* l, * r;
int h;
Node(int cc) :c(cc), h(1), l(NULL), r(NULL) {}
};
typedef Node* Tree;
int get_h(Tree t) {
if (!t)return 0;
return t->h;
}
int balancefact(Tree t) {
if (!t)return 0;
return get_h(t->r) - get_h(t->l);
}
void update(Tree t) {
if (!t)return;
t->h = max(get_h(t->l), get_h(t->r)) + 1;
}
Tree rot_right(Tree t) {
Tree q = t->l;
t->l = q->r;
q->r = t;
update(t);
update(q);
return q;
}
Tree rot_left(Tree t) {
Tree q = t->r;
t->r = q->l;
q->l = t;
update(t);
update(q);
return q;
}
Tree balance(Tree t) {
if (!t)return t;
update(t);
if (balancefact(t) == 2) {
if (balancefact(t->r) < 0)
t->r = rot_right(t->r);
return rot_left(t);
}
if (balancefact(t) == -2) {
if (balancefact(t->l) > 0)
t->l = rot_left(t->l);
return rot_right(t);
}
return t;
}
Tree add(int c, Tree t) {
if (!t) {
t = new Node(c);
return t;
}
if (t->c == c)return t;
if (t->c > c) {
t->r = add(c, t->r);
}
else {
t->l = add(c, t->l);
}
return balance(t);
}
Tree get_min(Tree t) {
if (!t->l)return t;
return get_min(t->l);
}
Tree erase(int c, Tree t) {
if (!t)return t;
if (t->c > c) {
t->r = erase(c, t->r);
}
else if (t->c < c) {
t->l = erase(c, t->l);
}
else if (t->l && t->r) {
t->c = get_min(t->r)->c;
t->r = erase(t->c, t->r);
}
else if (t->l)
t = t->l;
else
t = t->r;
return balance(t);
}
void draw(int x, int y, int c) {
CircleShape cir;
Text text;
text.setFont(font);
cir.setOrigin(Vector2f(r_size, r_size));
cir.setRadius(r_size);
cir.setOutlineColor(Color::Blue);
cir.setOutlineThickness(3);
text.setCharacterSize(144);
text.setString(to_string(c));
text.setOrigin(text.getLocalBounds().left + text.getLocalBounds().width / 2,
text.getLocalBounds().top + text.getLocalBounds().height / 2);
float min_size = min((r_size * 1.5f) / text.getLocalBounds().width, (r_size * 1.5f / 2) / text.getLocalBounds().height);
text.setScale(Vector2f(min_size, min_size));
cir.setPosition(x, y);
text.setPosition(Vector2f(x, y));
text.setFillColor(Color::Black);
window.draw(cir);
window.draw(text);
}
void draw_edg(int x1, int y1, int x2, int y2) {
if (x1 == 0 && y1 == 0)return;
RectangleShape line(Vector2f(sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)), 6));
line.setFillColor(Color::Cyan);
line.setPosition(Vector2f(x1, y1));
line.rotate(atan2(y2 - y1, x2 - x1) * 180.0 / atan2(0, -1));
window.draw(line);
}
int get(Tree t, int l, int h) {
if (!t)return 0;
int r = l;
if (t->l)
r = get(t->l, l, h - 1);
else
r += l_size * scale;
if (t->r)
r = get(t->r, r, h - 1);
else
r += l_size * scale;
if (!t->l && !t->r)
r += l_size;
int x_cor = l + (r - l) / 2;
int y_cor = h * h_size;
draw(x_cor, y_cor, t->c);
return r;
}
pair<int, pair<int, int>> get_edg(Tree t, int l, int h) {
if (!t)return make_pair(0, make_pair(0, 0));
int r = l;
pair<int, int> left = make_pair(0, 0);
pair<int, int> right = make_pair(0, 0);
if (t->l) {
pair<int, pair<int, int>> res = get_edg(t->l, l, h - 1);
r = res.first;
left = res.second;
}
else
r += l_size * scale;
if (t->r) {
pair<int, pair<int, int>> res = get_edg(t->r, r, h - 1);
r = res.first;
right = res.second;
}
else
r += l_size * scale;
if (!t->l && !t->r)
r += l_size;
int x_cor = l + (r - l) / 2;
int y_cor = h * h_size;
draw_edg(left.first, left.second, x_cor, y_cor);
draw_edg(right.first, right.second, x_cor, y_cor);
return make_pair(r, make_pair(x_cor, y_cor));
}
int main() {
view.reset(FloatRect(0, 0, window_w, window_h));
srand(time(NULL));
Tree t = 0;
Clock clock;
font.loadFromFile("CyrilicOld.TTF");
bool change = true;
int tim = 0;
int kadr = 0;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event) || change) {
float del_tim = clock.getElapsedTime().asMicroseconds();
del = del_tim / 4e4;
clock.restart();
tim += del_tim;
kadr++;
if (tim > 1e6) {
tim -= 1e6;
// cout << kadr << endl;
kadr = 0;
}
if (event.type == Event::Closed || Keyboard::isKeyPressed(Keyboard::Escape)) {
window.close();
}
if (Keyboard::isKeyPressed(Keyboard::Dash)) {
view.zoom(1.03f);
speed = speed * 1.03f;
wid = wid * 1.03f;
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Equal)) {
view.zoom(0.97f);
speed = speed * 0.97f;
wid = wid * 0.97f;
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Left)) {
view.move(Vector2f(-speed * del, 0));
wid += speed * del;
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Down)) {
view.move(Vector2f(0, speed * del));
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Up)) {
view.move(Vector2f(0, -speed * del));
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Right)) {
view.move(Vector2f(speed * del, 0));
wid += speed * del;
change = true;
}
if (Mouse::isButtonPressed(Mouse::Left)) {
for (int i = 0; i < 10; i++) {
int key = rand() - rand();
t = add(key, t);
}
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::A)) {
int key;
cin >> key;
t = add(key, t);
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::E)) {
int key;
cin >> key;
t = erase(key, t);
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::N)) {
view.zoom(wid_n / wid);
speed *= wid_n / wid;
wid = wid_n;
}
if (change) {
window.setView(view);
window.clear(Color(128, 106, 89));
get_edg(t, 0, get_h(t));
wid_n = get(t, 0, get_h(t));
hei_n = get_h(t) * h_size;
//change = false;
window.display();
}
}
}
return 0;
}
You initialize your RenderWindow object as a global variable. This happens before the start of your program, but there's no fixed order between different global variables. You probably get an error because other variables need to be initialized before you can create RenderWindow objects.
In this case, the program tries to write into the address 0x00000004. A global pointer that RenderWindow needs, probably still points to zero and not to a valid memory location. Thus the program crashes.
This problem is often referred to as the Static Initialization Order Fiasco.
The solution in this case is to only initialize window after main() starts. A possible way to do this is to use std::optional:
std::optional<RenderWindow> window = std::nullopt;
//...
int main() {
window = RenderWindow(VideoMode(window_w, window_h), "AVL Tree");
//...
}
You can also use a singleton if you'd like to initialize window more implicitly. Personally, I like to use the Meyers singleton in those cases:
auto get_window() {
static RenderWindow window(VideoMode(window_w, window_h), "AVL Tree");
return window;
}

Using uninitialized memory c++ box2D

I'm trying to create a simple Arkanoid game with Box2d, and right now I'm trying to detect the collision between the ball and the blocks, but when I debug the code, it keeps giving me the error: "The variable 'block' is being used without being initialized". What should I do the solve this problem? The blocks (red) are like this in the game:
#ifndef ARKANOID_H
#define ARKANOID_H
#include "../Framework/Test.h"
#include <vector>
struct Contact
{
Contact(const b2Vec2& normal, const b2Vec2& contactPt, float32 penetration = 0.0f)
: m_normal(normal)
, m_contactPt(contactPt)
, m_penetrationDepth(penetration) {}
b2Vec2 m_normal;
b2Vec2 m_contactPt;
float32 m_penetrationDepth;
};
class Ball
{
public:
Ball(): m_position(0.0f,0.0f), m_velocity(0.0f,0.0f), m_radius(0.5f){}
Ball(const b2Vec2& position,const b2Vec2& velocity, float32 radius = 0.5f)
: m_position(position)
, m_velocity(velocity)
, m_radius(radius)
{
m_invMass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f;
}
const b2Vec2& GetPosition(){return m_position;}
void SetPosition(const b2Vec2& newPosition){m_position = newPosition;}
float GetRadius() { return m_radius; }
void Update(float deltaTime);
void Render(DebugDraw& debugDraw);
void AddContact(const Contact& cp);
void HandleContacts();
void ApplyForce(const b2Vec2& force);
protected:
b2Vec2 m_position;
b2Vec2 m_velocity;
float32 m_radius;
float m_invMass;
float m_mass;
std::vector<Contact> m_contacts;
};
class Block
{
public:
Block( const b2Vec2 center, const b2Vec2& halfExtent );
void Render(DebugDraw& debugDraw);
b2Vec2 GetClosestPosition(const b2Vec2& pos);
protected:
b2AABB m_aabb;
};
class Paddle
{
public:
Paddle(b2Vec2& center, float width);
void Update(float deltaTime);
void Render(DebugDraw& debugDraw);
void SetSpeed(float speed) { m_speed = speed; }
b2Vec2 GetLeftPos() { return m_center - b2Vec2( m_width *0.5f, 0.0f ); }
b2Vec2 GetRightPos() { return m_center + b2Vec2( m_width *0.5f, 0.0f ); }
float GetHeight() { return m_center.y; }
void SetMoveRight();
void SetMoveLeft();
void Stop();
void SetWorldLimits(float min, float max);
protected:
b2Vec2 m_center;
float m_width;
float m_min_X;
float m_max_X;
b2Vec2 m_direction;
float m_speed;
};
class ArkanoidGame : public Test
{
public:
static Test* Create()
{
return new ArkanoidGame;
}
ArkanoidGame();
void CreateBlocks();
virtual void Step(Settings* settings);
void CheckCollisions();
void CheckOutofWorld();
bool IsOutofWorld(Ball* ball);
void UpdateBalls(float deltaTime);
void Render();
void Keyboard(unsigned char key);
void KeyboardUp(unsigned char key);
void AddBall();
void RemoveBall(Ball* ball);
void ApplyGravity();
b2Vec2 m_worldBoxMin;
b2Vec2 m_worldBoxMax;
Paddle m_paddle;
std::vector<Ball*> m_balls;
std::vector<Block*> m_blocks;
};
#endif
#include "../Framework/Render.h"
#include "Arkanoid.h"
#include <vector>
void Ball::Render(DebugDraw& debugDraw)
{
debugDraw.DrawSolidCircle(m_position, m_radius, b2Vec2(0.0f, 1.0f), b2Color(1.0f, 0.0f, 0.0f));
}
void Ball::Update(float deltaTime)
{
HandleContacts();
//Update position
//***To Do***
b2Vec2 m_force(b2Vec2_zero);
b2Vec2 acceleration = m_invMass * m_force;
m_velocity += deltaTime * acceleration;
m_position += deltaTime * m_velocity;
m_force = b2Vec2_zero;
}
void Ball::AddContact(const Contact& cp)
{
m_contacts.push_back(cp);
}
void Ball::HandleContacts()
{
//Resolve Collision
if (m_contacts.size() > 0)
{
//Prevent interpenetration => directly update position
b2Vec2 deltaPos(0.0f, 0.0f);
for (size_t i = 0; i<m_contacts.size(); ++i)
{
deltaPos += m_contacts[i].m_penetrationDepth * m_contacts[i].m_normal;
}
m_position += deltaPos;
//Average contact normal
b2Vec2 collisionNormal(0.0f, 0.0f);
for (size_t i = 0; i<m_contacts.size(); ++i)
{
collisionNormal += m_contacts[i].m_normal;
}
collisionNormal.Normalize();
//Update velocity
//***To Do*** ///fait
float restitution = 0.6f;
b2Vec2 vp = b2Dot(m_velocity, collisionNormal) * (collisionNormal);
b2Vec2 vt = m_velocity - vp;
m_velocity = vt + (-restitution * vp);
}
m_contacts.clear();
}
void Ball::ApplyForce(const b2Vec2& force)
{
b2Vec2 m_force(b2Vec2_zero);
m_force += force;
}
Block::Block(const b2Vec2 center, const b2Vec2& halfExtent)
{
m_aabb.lowerBound = center - halfExtent;
m_aabb.upperBound = center + halfExtent;
}
void Block::Render(DebugDraw& debugDraw)
{
debugDraw.DrawAABB(&m_aabb, b2Color(1.0f, 0.0f, 0.0f));
}
b2Vec2 Block::GetClosestPosition(const b2Vec2& pos)
{
b2Vec2 closestPosition;
if (pos.x < m_aabb.lowerBound.x)
{
if (pos.y < m_aabb.lowerBound.y)
{
closestPosition = m_aabb.lowerBound;
}
else if (pos.y > m_aabb.upperBound.y)
{
closestPosition = b2Vec2(m_aabb.lowerBound.x, m_aabb.upperBound.y);
}
else
{
closestPosition = b2Vec2(m_aabb.lowerBound.x, pos.y);
}
}
else if (pos.x > m_aabb.upperBound.x)
{
if (pos.y < m_aabb.lowerBound.y)
{
closestPosition = b2Vec2(m_aabb.upperBound.x, m_aabb.lowerBound.y);
}
else if (pos.y > m_aabb.upperBound.y)
{
closestPosition = m_aabb.upperBound;
}
else
{
closestPosition = b2Vec2(m_aabb.upperBound.x, pos.y);
}
}
else
{
if (pos.y < m_aabb.lowerBound.y)
{
closestPosition = b2Vec2(pos.x, m_aabb.lowerBound.y);
}
else if (pos.y > m_aabb.upperBound.y)
{
closestPosition = b2Vec2(pos.x, m_aabb.upperBound.y);
}
else
{
closestPosition = pos;
}
}
return closestPosition;
}
Paddle::Paddle(b2Vec2& center, float width)
: m_center(center)
, m_width(width)
, m_direction(0.0f, 0.0f)
, m_speed(12.0f)
, m_min_X(-b2_maxFloat)
, m_max_X(b2_maxFloat)
{
}
void Paddle::SetWorldLimits(float min, float max)
{
//***To Do***
}
void Paddle::Update(float deltaTime)
{
//***To Do***
}
void Paddle::Render(DebugDraw& debugDraw)
{
b2Vec2 halfExtent(m_width*0.5f, 0.0f);
debugDraw.DrawSegment(m_center + halfExtent, m_center - halfExtent, b2Color(0.0f, 1.0f, 0.0f));
}
void Paddle::SetMoveRight()
{
m_direction = b2Vec2(1.0f, 0.0f);
}
void Paddle::SetMoveLeft()
{
m_direction = b2Vec2(-1.0f, 0.0f);
}
void Paddle::Stop()
{
m_direction = b2Vec2_zero;
}
ArkanoidGame::ArkanoidGame()
: m_worldBoxMin(-25.0f,0.0f)
, m_worldBoxMax(25.0f,50.0f)
, m_paddle(b2Vec2(0.0f, 2.0f), 4.0f)
{
m_paddle.SetWorldLimits(m_worldBoxMin.x, m_worldBoxMax.x);
CreateBlocks();
}
void ArkanoidGame::CreateBlocks()
{
b2Vec2 blockHalfExtent(3.0f, 1.0f);
int nbColumn = 6;
int nbNbRow = 3;
b2Vec2 startPos = b2Vec2(-15.0f, 35.0f);
for (int i = 0; i < nbNbRow; i++)
{
for (int j = 0; j < nbColumn; j++)
{
b2Vec2 pos = startPos + b2Vec2(blockHalfExtent.x * 2.0f * j, blockHalfExtent.y * 2.0f * i);
Block* newBlock = new Block(pos, blockHalfExtent);
m_blocks.push_back(newBlock);
}
}
}
void ArkanoidGame::Step(Settings* settings)
{
float timeStep = settings->hz > 0.0f ? 1.0f / settings->hz : float32(0.0f);
ApplyGravity();
m_paddle.Update(timeStep);
UpdateBalls(timeStep);
CheckCollisions();
CheckOutofWorld();
Render();
}
void ArkanoidGame::UpdateBalls(float deltaTime)
{
for (size_t i = 0; i < m_balls.size(); ++i)
{
m_balls[i]->Update(deltaTime);
}
}
void ArkanoidGame::CheckCollisions()
{
//Box interior normals
b2Vec2 rightN(-1.0f,0.0f);
b2Vec2 leftN(1.0f,0.0f);
b2Vec2 upN(0.0f,-1.0f);
b2Vec2 downN(0.0f, 1.0f);
b2Vec2 blockHalfExtent(3.0f, 1.0f); /////
Block* block;
//Check collisions for all particules
std::vector<Ball*>::iterator it;
for (it=m_balls.begin(); it!= m_balls.end(); ++it)
{
Ball* ball = *it;
b2Vec2 pos = ball->GetPosition();
float32 radius = ball->GetRadius();
//Check collisions for each wall
//Left
float left = pos.x - radius;
if( left <= m_worldBoxMin.x )
{
ball->AddContact( Contact(leftN, b2Vec2( left, pos.y ), m_worldBoxMin.x - left ) );
}
//Right
float right = pos.x + radius;
if( right >= m_worldBoxMax.x )
{
ball->AddContact(Contact(rightN, b2Vec2( right, pos.y ), right - m_worldBoxMax.x ) );
}
//Up
float up = pos.y + radius;
if( up >= m_worldBoxMax.y )
{
ball->AddContact(Contact(upN, b2Vec2( pos.x, up ), up - m_worldBoxMax.y ) );
}
//Check Collision with paddle
//***To Do***
//Check collisions with blocks
//***To Do***
Block*block;
b2Vec2 toClosest = ball->GetPosition()- block->GetClosestPosition(pos);
float distance = toClosest.Normalize();
float penetrationDepth = distance - ball->GetRadius();
if (penetrationDepth < 0.0f)
{
ball->HandleContacts();
}
//Add contact and destroy the block
}
}
void ArkanoidGame::CheckOutofWorld()
{
for (size_t i = 0; i < m_balls.size(); )
{
if (IsOutofWorld(m_balls[i]))
{
//Remove ball
RemoveBall(m_balls[i]);
}
else
{
i++;
}
}
}
bool ArkanoidGame::IsOutofWorld(Ball* ball)
{
//***To Do***
return false;
}
void ArkanoidGame::Render()
{
m_paddle.Render(m_debugDraw);
//Render Ball
for (size_t i = 0; i < m_balls.size();++i)
{
m_balls[i]->Render(m_debugDraw);
}
//Render Blocks
for (size_t i = 0; i < m_blocks.size(); ++i)
{
m_blocks[i]->Render(m_debugDraw);
}
//Render Box
b2Vec2 box[4];
box[0].Set(m_worldBoxMin.x, m_worldBoxMin.y);
box[1].Set(m_worldBoxMin.x, m_worldBoxMax.y);
box[2].Set(m_worldBoxMax.x, m_worldBoxMax.y);
box[3].Set(m_worldBoxMax.x, m_worldBoxMin.y);
m_debugDraw.DrawSegment(box[0], box[1], b2Color(0.0f, 0.0f, 1.0f));
m_debugDraw.DrawSegment(box[1], box[2], b2Color(0.0f, 0.0f, 1.0f));
m_debugDraw.DrawSegment(box[2], box[3], b2Color(0.0f, 0.0f, 1.0f));
}
void ArkanoidGame::Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
{
m_paddle.SetMoveLeft();
}
break;
case 'd':
{
m_paddle.SetMoveRight();
}
break;
case 'n':
{
AddBall();
}
break;
}
}
void ArkanoidGame::KeyboardUp(unsigned char key)
{
switch (key)
{
case 'a':
case 'd':
m_paddle.Stop();
break;
}
}
void ArkanoidGame::AddBall()
{
float angle = RandomFloat(-b2_pi*0.25f, b2_pi*0.25f);
b2Rot rot(angle);
float speed = RandomFloat(10.0f, 20.0f);
b2Vec2 dir(0.0f, speed);
Ball* ball = new Ball(b2Vec2(0.0f, 5.0f), b2Mul(rot, dir));
m_balls.push_back(ball);
}
void ArkanoidGame::RemoveBall(Ball* ball)
{
std::vector<Ball*>::iterator it = m_balls.begin();
while (it != m_balls.end())
{
if ((*it) == ball)
{
std::swap(*it, m_balls.back());
m_balls.pop_back();
break;
}
++it;
}
}
void ArkanoidGame::ApplyGravity()
{
for (Ball* ball : m_balls)
{
ball->ApplyForce(b2Vec2(0.0f,-9.81f));
}
}
You have the following code:
Block*block;
b2Vec2 toClosest = ball->GetPosition()- block->GetClosestPosition(pos);
You never assign anything to block, so which block should it be getting the closest position of?
My guess is you want to loop through all the blocks, so you need another iterator, something like this:
std::vector<Block*>::iterator itb;
for (itb = m_blocks.begin); itb != m_blocks.end(); ++itb) {
b2Vec2 toClosest = ball->getPosition - itb->getClosestPosition(pos);
float distance = toClosest.Normalize();
float penetrationDepth = distance - ball->GetRadius();
if (penetrationDepth < 0.0f)
{
ball->HandleContacts();
}
}

A star algorithm not working because of pointer to parent, help fixing it

I have been lately working in an implementation of the a* algorithm and I got a problem.
What happens is that in here:
std::list<Node> openList;
std::list<Node> closedList;
startNode.calc(map, endPos);
openList.push_back(startNode);
while (!openList.empty())
{
auto min = std::min_element(openList.begin(), openList.end());
auto current = Node(*min);
current.calc(map, endPos);
closedList.push_back(current);
openList.remove(current);
I'm making current to be equal to the minimal element in openList.
And later in the code
if (inOpen == openList.end())
{
successor.calc(map, endPos);
successor.parent = &current;
openList.push_back(successor);
}
I'm setting the address of current to be successor's parent.
What happens, is that in the next iteration, it seems that current is defined in the same address, successor's parent will be equal to the new current.
What should I use instead of a Node*, because that seems to be what's making my code not work.
Full algorithm code:
bool Solver::aStar()
{
if ((map.getDangerElement(startPos) == 'X') || map.getDangerElement(endPos) == 'X')
return false;
Node startNode(startPos);
Node goalNode(Vector2(endPos.x - 1, endPos.y - 1));
std::list<Node> openList;
std::list<Node> closedList;
startNode.calc(map, endPos);
openList.push_back(startNode);
while (!openList.empty())
{
auto current = Node(*std::min_element(openList.begin(), openList.end()));
current.calc(map, endPos);
closedList.push_back(current);
openList.remove(current);
for (auto& direction : directions)
{
Node successor(direction.position + current.position);
if (map.getDangerElement(successor.position) == 'X' ||
successor.position.x >= map.getSize() - 1 || successor.position.y >= map.getSize() - 1 ||
successor.position.x < 0 || successor.position.y < 0 ||
std::find(closedList.begin(), closedList.end(), successor) != closedList.end())
{
continue;
}
successor.calc(map, endPos);
auto inOpen = std::find(openList.begin(), openList.end(), successor);
if (inOpen == openList.end())
{
auto curr = &current;
successor.parent = curr;
successor.calc(map, endPos);
openList.push_back(successor);
}
else
{
if (successor.G < inOpen->G)
{
auto* curr = &current;
successor.parent = curr;
}
}
}
#ifdef DEBUG
for (auto a : closedList)
{
map.setElement(a.position, 'Y');
}
#endif
if (current == goalNode) break;
}
if (openList.size() == 0)
{
std::cout << "There's no solution to this map";
return false;
}
map.display();
return true;
}
Full code:
Vector2.h
#pragma once
struct Vector2
{
int x, y;
Vector2(int, int);
Vector2();
Vector2 operator +(const Vector2&);
};
Vector2.cpp
#include "Vector2.h"
Vector2::Vector2(int _x, int _y) : x(_x), y(_y)
{ }
Vector2::Vector2()
{ }
Vector2 Vector2::operator+(const Vector2& other)
{
Vector2 temp;
temp.x = this->x + other.x;
temp.y = this->y + other.y;
return temp;
}
map.h
#pragma once
#include "vector2.h"
#include <vector>
#include <iostream>
#include <random>
#include <algorithm>
class Map
{
Vector2 startPos, endPos;
std::vector<char> data;
std::vector<char> datad;
int size;
void setDangerElement(Vector2 position, char);
void fillDangerMap();
Vector2 clamp(int min, int max, Vector2 position) const;
public:
Map(int size, Vector2 startPosition, Vector2 endPosition);
Map();
void setSize(int size);
void fill(char, char, char, char, char);
void display();
char getElement(Vector2 position) const;
char getDangerElement(Vector2 position) const;
int getSize() const;
void setElement(Vector2 position, char element);
};
std::mt19937& getRandomEngine();
map.cpp
#include "map.h"
Map::Map(int _size, Vector2 _startPos, Vector2 _endPos) : size(_size), startPos(_startPos), endPos(_endPos)
{
data.resize(size * size);
datad.resize(size * size);
}
Map::Map()
{ }
Vector2 Map::clamp(int min, int max, Vector2 position) const
{
if (position.y < 0) position.y = 0;
if (position.x < 0) position.x = 0;
if (position.y > size) position.y = size;
if (position.x > size) position.x = size;
return position;
}
void Map::fill(char fillStartWith, char fillEndWith, char fillGravWheelWith, char fillAsteroidWith, char fillElseWith)
{
auto a = (size * size) * 0.1 / 3;
auto b = (size * size) * 0.3 / 3;
for(int i = 0; i < size * size; ++i){
if(i < a) data[i] = fillGravWheelWith;
else if(i < b) data[i] = fillAsteroidWith;
else data[i] = fillElseWith;
}
std::shuffle(data.begin(), data.end(), getRandomEngine());
setElement(startPos, fillStartWith);
setElement(endPos, fillEndWith);
fillDangerMap();
}
void Map::display()
{
for(int i = 1; i <= size * size; ++i)
{
std::cout << data[i - 1] << " ";
if (!(i % size))
std::cout << "\n";
}
}
void Map::setSize(int _size)
{
size = _size;
data.resize(size * size);
}
char Map::getElement(Vector2 position) const
{
position = clamp(0, size, position);
position.y *= size;
return data[position.x + position.y];
}
char Map::getDangerElement(Vector2 position) const
{
position = clamp(0, size, position);
position.y *= size;
return datad[position.x + position.y];
}
void Map::fillDangerMap()
{
for (int i = 0; i < size * size; ++i) datad[i] = '.';
for(int y = 0; y < size; ++y){
for(int x = 0; x < size; ++x){
Vector2 current(x,y);
if (getElement(current) == 'E') setDangerElement(current, 'E');
else if (getElement(current) == 'S') setDangerElement(current, 'S');
else if (getElement(current) == 'A') setDangerElement(current, 'X');
if (getElement(current) == 'G' && x == 0){
setDangerElement(current, 'X');
setDangerElement(Vector2(x, y + 1), 'X');
setDangerElement(Vector2(x, y - 1), 'X');
setDangerElement(Vector2(x + 1, y + 1), 'X');
setDangerElement(Vector2(x + 1, y), 'X');
setDangerElement(Vector2(x + 1, y - 1), 'X');
}
else if (getElement(current) == 'G' && y == 0){
setDangerElement(current, 'X');
setDangerElement(Vector2(x, y + 1), 'X');
setDangerElement(Vector2(x - 1, y), 'X');
setDangerElement(Vector2(x - 1, y + 1), 'X');
setDangerElement(Vector2(x + 1, y + 1), 'X');
setDangerElement(Vector2(x + 1, y), 'X');
}
else if (getElement(current) == 'G' && x == size - 1){
setDangerElement(Vector2(x, y), 'X');
setDangerElement(Vector2(x, y + 1), 'X');
setDangerElement(Vector2(x, y - 1), 'X');
setDangerElement(Vector2(x - 1, y), 'X');
setDangerElement(Vector2(x - 1, y - 1), 'X');
setDangerElement(Vector2(x - 1, y + 1), 'X');
}
else if (getElement(current) == 'G' && y == size - 1){
setDangerElement(current, 'X');
setDangerElement(Vector2(x, y - 1), 'X');
setDangerElement(Vector2(x - 1, y), 'X');
setDangerElement(Vector2(x - 1, y - 1), 'X');
setDangerElement(Vector2(x + 1, y), 'X');
setDangerElement(Vector2(x + 1, y - 1), 'X');
}
else if (getElement(current) == 'G'){
setDangerElement(current, 'X');
setDangerElement(Vector2(x, y + 1), 'X');
setDangerElement(Vector2(x, y - 1), 'X');
setDangerElement(Vector2(x - 1, y), 'X');
setDangerElement(Vector2(x - 1, y - 1), 'X');
setDangerElement(Vector2(x - 1, y + 1), 'X');
setDangerElement(Vector2(x + 1, y + 1), 'X');
setDangerElement(Vector2(x + 1, y), 'X');
setDangerElement(Vector2(x + 1, y - 1), 'X');
}
}
}
}
void Map::setElement(Vector2 position, char elem)
{
position = clamp(0, size, position);
position.y *= size;
data[position.x + position. y] = elem;
}
void Map::setDangerElement(Vector2 position, char elem)
{
position = clamp(0, size, position);
position.y *= size;
datad[position.x + position.y] = elem;
}
int Map::getSize() const
{
return size;
}
std::mt19937& getRandomEngine()
{
static std::mt19937 randomEngine(std::random_device{}());
return randomEngine;
}
node.h
#pragma once
#include "map.h"
#include <list>
#include <cmath>
struct Node
{
Vector2 position;
int G, H, F;
Node* parent = nullptr;
Node();
Node(const Node& other) = default;
Node(Vector2 pos);
void calc(const Map&, const Vector2&);
bool operator==(const Node&);
bool operator<(const Node&);
};
node.cpp
#include "node.h"
Node::Node()
{ }
Node::Node(Vector2 pos) : position(pos)
{ }
void Node::calc(const Map& map, const Vector2& endPos)
{
H = static_cast<int>((abs(static_cast<double>(position.x - endPos.x)) + abs(static_cast<double>(position.y - endPos.y))));
G = parent ? parent->G + 1 : 1;
F = G + H;
}
bool Node::operator==(const Node& other)
{
return (position.x == other.position.x && position.y == other.position.y);
}
bool Node::operator<(const Node& other)
{
return(F < other.F);
}
solver.h
#pragma once
#include "node.h"
class Solver
{
Vector2 startPos, endPos;
Map map;
std::vector<Node> directions;
public:
Solver(const int&, const Vector2&, const Vector2&);
void displayMap();
bool aStar();
};
solver.cpp
#include "solver.h"
#define DEBUG
Solver::Solver(const int& size, const Vector2& _startPos, const Vector2& _endPos) : startPos(_startPos), endPos(_endPos)
{
Map temp(size, startPos, endPos);
map = temp;
map.fill('S', 'E', 'G', 'A', '.');
map.display();
directions.resize(8);
directions[0] = Node(Vector2 (-1 ,1));
directions[1] = Node(Vector2(-1, 0));
directions[2] = Node(Vector2(-1, -1));
directions[3] = Node(Vector2(0, 1));
directions[4] = Node(Vector2(0, -1));
directions[5] = Node(Vector2(1, 1));
directions[6] = Node(Vector2(1, 0));
directions[7] = Node(Vector2(1, -1));
}
void Solver::displayMap()
{
map.display();
}
bool Solver::aStar()
{
if ((map.getDangerElement(startPos) == 'X') || map.getDangerElement(endPos) == 'X')
return false;
Node startNode(startPos);
Node goalNode(Vector2(endPos.x - 1, endPos.y - 1));
std::list<Node> openList;
std::list<Node> closedList;
startNode.calc(map, endPos);
openList.push_back(startNode);
while (!openList.empty())
{
auto current = Node(*std::min_element(openList.begin(), openList.end()));
current.calc(map, endPos);
closedList.push_back(current);
openList.remove(current);
for (auto& direction : directions)
{
Node successor(direction.position + current.position);
if (map.getDangerElement(successor.position) == 'X' ||
successor.position.x >= map.getSize() - 1 || successor.position.y >= map.getSize() - 1 ||
successor.position.x < 0 || successor.position.y < 0 ||
std::find(closedList.begin(), closedList.end(), successor) != closedList.end())
{
continue;
}
successor.calc(map, endPos);
auto inOpen = std::find(openList.begin(), openList.end(), successor);
if (inOpen == openList.end())
{
auto curr = &current;
successor.parent = curr;
successor.calc(map, endPos);
openList.push_back(successor);
}
else
{
if (successor.G < inOpen->G)
{
auto* curr = &current;
successor.parent = curr;
}
}
}
#ifdef DEBUG
for (auto a : closedList)
{
map.setElement(a.position, 'Y');
}
#endif
if (current == goalNode) break;
}
if (openList.size() == 0)
{
std::cout << "There's no solution to this map";
return false;
}
map.display();
return true;
}
source.cpp
#include "solver.h"
int main()
{
const int SIZE = 20;
const Vector2 startPos(0, 0);
const Vector2 endPos(SIZE - 1, SIZE - 1);
Solver solve(SIZE, startPos, endPos);
if (solve.aStar()){
std::cout << "\nMap has been successfully solved.\nMap:\n";
solve.displayMap();
}
else std::cout << "\nThere is no path from the start position to the end position in this map.\n";
std::cin.get();
return 0;
}
Thanks!
As the comment suggested, you are storing the address of a local variable inside the container. When that local goes out of scope, your code will exhibit undefined behavior.
Also, the reason why you see the same address being stored is that you are creating a new local instance of current, and by chance, the new local instance has the same address as the old (now destroyed) instance of current.
However, taking a look at the offending function, I see that you are storing current in a std::list. You may have a way of accomplishing what you are seeking with a very minor change.
Since you are doing this in your solver function:
auto current = Node(*std::min_element(openList.begin(), openList.end()));
current.calc(map, endPos);
closedList.push_back(current); // < -- This could be your lifeline
the last line creates a copy of current, and then places it on the back of a std::list. Why is that promising? It is promising because,
You know exactly where the current copy is located (at the back of
a std::list) and
A pointer to a std::list entry is guaranteed to be valid, in
scope, etc. even if the std::list changes size provided that the entry is still in the list.
So given this, the fix to your code should be very simple. Further down in the function you are doing this:
if (inOpen == openList.end())
{
auto curr = &current;
successor.parent = curr;
//...
Instead, do this:
if (inOpen == openList.end())
{
auto curr = &closedList.back();
successor.parent = curr;
//...
We are now being returned a reference to the last item that was pushed onto the list, and getting the address of this item.
Now, the caveat is that closedList better not go out of scope, and that item you added to the list doesn't get removed while you are holding the address of the item.
Whether this fixes all your issues, I am not sure. But it is something you should try.
The bottom line is that if you're using a std::list to store objects, getting pointers to those objects in the list is perfectly safe to do as long as
The std::list is in scope and
The item you have a pointer to is not removed from the std::list.

Unable to access of members of pointed object from inside array or vector of pointers

OK, I have a vector (have also tried an array) of pointers to objects class GameObject-
//GameObject* objPriority_vec [oc+1];
std::vector<GameObject*> objPriority_vec(oc+1);
and have successfully filled it with pointers to objects of derived classes of GameObject
(MapObject and PlayerCharacter)
for(int o_r = 1; o_r <= oc; o_r++)
{
std::string render_ref = CurrentArea->ObjectRef[o_r];
MapObject* render_obj = CurrentArea->ObjectMap[render_ref];
objPriority_vec[o_r] = render_obj;
}
objPriority_vec[0] = Player_1; // Player_1 is a pointer to obj
// PlayerCharacter
But, very strangely, I cannot seem to access any of the members of any of the objects pointed to
by any of the pointers in the vector/array, even though I have verified that they are in there. For
sake of debugging I have:
GameObject* prioritycheck = objPriority_vec[0]; //has been explicitly declared
//as Player_1
//When tried one a time
if( prioritycheck == Player_1 ) gameRunning = false; // returns false
//(when it should)
if( Player_1->Pos_y > 500) gameRunning = false; // returns false
if( objPriority_vec[0]->Pos_y > 500) gameRunning = false; // does not
if( prioritycheck->Pos_y > 500) gameRunning = false; // does not
So once the pointer has been stored in the vector, it seems to know what it is,
but not what any of its members are... any ideas? I can't seem to comprehend a universe
where this logic can exist...
Class Definitions:
class GameObject
{
public:
std::string Graphic_path;
int height;
int width;
int Pos_x;
int Pos_y;
int Vel;
m_dir Dir;
bool moving;
bool colliding;
CollisionBox cCollisionBox;
virtual void Move(){}
virtual void Show(SDL_Surface*, SDL_Surface*){}
virtual void Add(){}
GameObject() {Graphic_path = "NULL"; Pos_x = 0; Pos_y = 0; height = 0; width = 0;}
};
class MapObject : public GameObject
{
public:
SDL_Surface* Graphic;
std::string Graphic_path;
int height;
int width;
int Pos_x;
int Pos_y;
int Vel;
m_dir Dir;
bool moving;
bool colliding;
CollisionBox cCollisionBox;
bool SetCollisionBox(int x, int y, int w, int h)
{
cCollisionBox.h = h;
cCollisionBox.w = w;
cCollisionBox.x_off = x;
cCollisionBox.y_off = y;
}
bool CheckCollide(){return false;}
void HandleCollide (int vel_x, int vel_y, int vel, m_dir dir)
{
switch (dir)
{
case Up:
break;
case Down:
break;
case Left:
break;
case Right:
break;
}
}
virtual void Move(int v, m_dir dir)
{
switch (dir)
{
case Up:
Pos_y -= v;
break;
case Down:
Pos_y += v;
break;
case Left:
Pos_x -= v;
break;
case Right:
Pos_x += v;
break;
}
}
void StandStill()
{
Vel = 0;
moving = false;
}
virtual void Show(SDL_Surface*, SDL_Surface*){}
virtual void Add(){}
MapObject()
{
Graphic = NULL; Graphic_path = "NULL";
Pos_x = 0; Pos_y = 0;
height = 0; width = 0;
colliding = false; moving = false;
}
};
class PlayerCharacter : public GameObject
{
public:
int Pos_x;
int Pos_y;
int Vel;
int Vel_x;
int Vel_y;
int frame;
int frame_count;
m_dir Dir;
bool moving;
bool colliding;
SDL_Rect CharClip[20];
CollisionBox cCollisionBox;
void SetClip_Walk()
{
int CharWidth = 22;
int CharHeight = 45;
int CharGap = 6;
for (int z = 0; z <= 19; z++)
{
CharClip[ z ].x = (z * CharWidth) + (z * CharGap);
CharClip[ z ].y = 0;
CharClip[ z ].w = CharWidth;
CharClip[ z ].h = CharHeight;
}
}
PlayerCharacter()
{
Pos_x = 0; Pos_y = 0; Vel_x = 0; Vel_y = 0;
Vel = 0; moving = false; colliding = false;
frame = 0; frame_count = 0;
Dir = Down;
SetClip_Walk();
}
bool SetCollisionBox(int x, int y, int w, int h)
{
cCollisionBox.h = h;
cCollisionBox.w = w;
cCollisionBox.x_off = x;
cCollisionBox.y_off = y;
}
void HandleCollide ()
{
Pos_y -= (Vel_y);
Pos_x -= (Vel_x);
cCollisionBox.x = Pos_x + cCollisionBox.x_off;
cCollisionBox.y = Pos_y + cCollisionBox.y_off;
}
void Move(int v_x, int v_y, int v, m_dir dir)
{
switch (dir)
{
case Up:
Pos_y += v_y;
break;
case Down:
Pos_y += v_y;
break;
case Left:
Pos_x += v_x;
break;
case Right:
Pos_x += v_x;
break;
}
cCollisionBox.x = Pos_x + cCollisionBox.x_off;
cCollisionBox.y = Pos_y + cCollisionBox.y_off;
}
void StandStill()
{
Vel = 0; Vel_x = 0; Vel_y = 0;
moving = false;
colliding = false;
}
void Show(SDL_Surface* source, SDL_Surface* dest)
{
if (Vel != 0) frame_count++;
if (frame_count > 3) {frame++; frame_count = 0;}
if (frame > 4) frame = 1;
if (Vel == 0) {frame = 0; frame_count = 0;}
switch (Dir)
{
case Up:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame]);
break;
case Down:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame+5]);
break;
case Left:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame+10]);
break;
case Right:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame+15]);
break;
}
}
};
Thank you, all your help and time is greatly appreciated!
You have a base class GameObject which has instance variables Pos_x, Pos_y, etc. You have then subclassed this with MapObject, PlayerObject which have their own instance variables of the same name. This results in each of the derived classes having two of these variables - (one for the base, site for the derived).
You then access these via a pointer to GameObject* which will only provide access to the base class instance variables. As your tests show these do not contain the values you are expecting.
You do not need to declare these instance variables in both base and subclasses. It does not look like having separate variables is serving any purpose in this case; rather it is stopping your code from working. The defined class should only define additional fields on top of those in the base class.
"If you want to compare arbitrary class hierarchies, the safe bet is to make them polymorphic and use dynamic_cast."
See https://stackoverflow.com/a/5662867/912757
try to change for example this statement
if( prioritycheck == Player_1 ) gameRunning = false;
to
if( dynamic_cast<PlayerCharacter *>( prioritycheck ) == Player_1 ) gameRunning = false;