When I try to compile the following code:
Alien::Action::Action(ActionType type, float x, float y) {
Action::type = type;
pos = Vec2(x, y);
}
Alien::Alien(float x, float y, int nMinions) {
srand(time(NULL));
sp = Sprite("img/alien.png");
box = Rect(x, y, sp.GetWidth(), sp.GetHeight());
box.x = x - box.h/2;
box.y = y - box.w/2;
hitpoints = 100;
speed.x = 0.5;
speed.y = 0.5;
minionArray = std::vector<Minion>();
for(int i = 0; i < nMinions; i++) {
int a = rand()%501;
float b = a/1000.0;
float c = b+1;
minionArray.emplace_back(Minion(get(), i*(360/nMinions), c));
}
taskQueue = std::queue<Action>();
}
The IDE (Eclipse) gives the following error message: "undefined reference to 'vtable for Alien'" (line 6 of the code). Since there's no virtual method inside Alien, I don't know the cause of the error. The following is the header file for Alien:
#ifndef ALIEN_H_
#define ALIEN_H_
#include "GameObject.h"
class Alien: public GameObject {
private:
class Action {
public:
enum ActionType {MOVE, SHOOT};
ActionType type;
Action(ActionType type, float x, float y);
Vec2 pos;
};
int hitpoints;
std::queue<Action> taskQueue;
std::vector<Minion> minionArray;
public:
Alien(float x, float y, int nMinions);
~Alien();
void Update(float dt);
void Render();
Alien* get();
bool IsDead();
};
#endif
The code for GameObject is :
#include "GameObject.h"
#include "InputManager.h"
#include "Camera.h"
#include "State.h"
GameObject::~GameObject() {
}
GameObject* GameObject::get() {
return this;
}
Minion::~Minion() {
}
Minion::Minion(GameObject* minionCenter, float arcOffset, float minionSize) {
sp = Sprite("img/minion.png");
center = minionCenter;
translation = arcOffset;
box = Rect(center->box.GetCenter().x+(cos(translation*M_PI/180)*200)-(sp.GetWidth()/2),
center->box.GetCenter().y+(sin(translation*M_PI/180)*200)-(sp.GetHeight()/2),
sp.GetWidth(), sp.GetHeight());
}
void Minion::Shoot(Vec2 pos) {
State::AddObject(new BulletWheel(box.GetCenter().x, box.GetCenter().y, center->box.GetCenter().GetDX(pos.x),
center->box.GetCenter().GetDY(pos.y), center->box.GetCenter().GetDS(pos), 0.3,
translation, center->box.GetCenter(), "img/minionbullet1.png"));
}
void Minion::Update(float dt) {
if(translation < 360)
translation += 0.03*dt;
else
translation += 0.03*dt-360;
/*rotation = translation-90;*/
if(rotation < 360)
rotation += 0.15*dt;
else
rotation += 0.15*dt-360;
box.x = center->box.GetCenter().x+(200*cos((translation)*M_PI/180))-(box.w/2);
box.y = center->box.GetCenter().y+(200*sin((translation)*M_PI/180))-(box.h/2);
}
void Minion::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
}
bool Minion::IsDead() {
return false;
}
Bullet::Bullet(float x, float y, float dx, float dy, float maxDistance, float speed, std::string sprite) {
sp = Sprite(sprite);
box = Rect(x-(sp.GetWidth()/2), y-(sp.GetHeight()/2), sp.GetWidth(), sp.GetHeight());
Bullet::speed = Vec2(speed*(dx/maxDistance), speed*(dy/maxDistance));
distanceLeft = maxDistance;
rotation = atan2(dy, dx)*(180/M_PI);
}
void Bullet::Update(float dt) {
if(distanceLeft > 0) {
box.x += speed.x*dt;
box.y += speed.y*dt;
distanceLeft -= pow(pow(speed.x*dt,2)+pow(speed.y*dt,2),0.5);
}
}
void Bullet::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
}
bool Bullet::IsDead() {
return (distanceLeft < 1) ? true : false;
}
Bullet* Bullet::get() {
return this;
}
BulletWheel::BulletWheel(float x, float y, float dx, float dy, float maxDistance, float speed, float arcOffset, Vec2 center, std::string sprite) {
sp = Sprite(sprite);
sp.SetScaleX(2);
sp.SetScaleY(2);
box = Rect(x-(sp.GetWidth()/2), y-(sp.GetHeight()/2), sp.GetWidth(), sp.GetHeight());
BulletWheel::speed = Vec2(speed*(dx/maxDistance), speed*(dy/maxDistance));
distanceLeft = maxDistance;
rotation = atan2(dy, dx)*(180/M_PI);
translation = arcOffset;
BulletWheel::center = center;
}
void BulletWheel::Update(float dt) {
if(translation < 360)
translation += 0.1*dt;
else
translation += 0.1*dt-360;
if(distanceLeft > 0.01) {
center.x += speed.x*dt;
center.y += speed.y*dt;
box.x = center.x+(200*cos((translation)*M_PI/180))-(box.w/2);
box.y = center.y+(200*sin((translation)*M_PI/180))-(box.h/2);
distanceLeft -= pow(pow(speed.x*dt,2)+pow(speed.y*dt,2),0.5);
}
}
void BulletWheel::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
}
bool BulletWheel::IsDead() {
return distanceLeft < 1;
}
BulletWheel* BulletWheel::get() {
return this;
}
and its header file is:
#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_
#include "Sprite.h"
#include "Rect.h"
#include "Vec2.h"
#include <queue>
#include <vector>
#include <cmath>
#include <ctime>
class GameObject{
private:
public:
virtual ~GameObject();
virtual void Update(float dt) = 0;
virtual void Render() = 0;
virtual bool IsDead() = 0;
virtual GameObject* get();
int rotation = 0;
int translation = 0;
Sprite sp = Sprite();
Vec2 speed = Vec2();
Rect box = Rect();
};
class Minion : public GameObject {
private:
GameObject* center;
public:
Minion(GameObject* minionCenter, float arcOffset, float minionSize = 1);
~Minion();
void Shoot(Vec2 pos);
void Update(float dt);
void Render();
bool IsDead();
Minion* get();
};
class Bullet : public GameObject {
private:
float distanceLeft;
public:
Bullet(float x, float y, float dx, float dy, float maxDistance, float speed, std::string sprite);
void Update(float dt);
void Render();
bool IsDead();
Bullet* get();
};
class BulletWheel : public GameObject {
private:
float distanceLeft;
Vec2 center;
public:
BulletWheel(float x, float y, float dx, float dy, float maxDistance, float speed, float arcOffset, Vec2 center, std::string sprite);
void Update(float dt);
void Render();
bool IsDead();
BulletWheel* get();
};
#endif /* GAMEOBJECT_H_ */
There are the virtual functions of GameObject, declared inside Alien.cpp:
void Alien::Update(float dt) {
if(rotation > 0)
rotation -= 0.1*dt;
else
rotation -= 0.1*dt+360;
if(InputManager::GetInstance().MousePress(RIGHT_MOUSE_BUTTON)) {
taskQueue.push(Action(Action::MOVE,(InputManager::GetInstance().GetMouseX() + Camera::GetInstance().pos.x - (box.w/2)),
(InputManager::GetInstance().GetMouseY() + Camera::GetInstance().pos.y - (box.h/2))));
}
if(InputManager::GetInstance().MousePress(LEFT_MOUSE_BUTTON)) {
taskQueue.push(Action(Action::SHOOT,(InputManager::GetInstance().GetMouseX() + Camera::GetInstance().pos.x),
(InputManager::GetInstance().GetMouseY() + Camera::GetInstance().pos.y)));
}
if(taskQueue.size() > 0) {
Vec2 pos = taskQueue.front().pos;
if(taskQueue.front().type == Action::MOVE) {
float cos = (box.GetDX(pos.x)/box.GetDS(pos));
float sin = (box.GetDY(pos.y)/box.GetDS(pos));
if(cos != cos) {
cos = 0;
}
if(sin != sin) {
sin = 0;
}
if((box.x+speed.x*cos*dt > pos.x && pos.x > box.x) || (box.x+speed.x*cos*dt < pos.x && pos.x < box.x)) {
box.x = pos.x;
}
else {
box.x += speed.x*cos*dt;
}
if((box.y+speed.y*sin*dt > pos.y && pos.y > box.y) || (box.y+speed.y*sin*dt < pos.y && pos.y < box.y)) {
box.y = pos.y;
}
else {
box.y += speed.y*sin*dt;
}
if(box.x == pos.x && box.y == pos.y) {
taskQueue.pop();
}
}
else {
for(unsigned i = 0; i < minionArray.size(); i++) {
minionArray.at(i).Shoot(pos);
taskQueue.pop();
}
}
}
for(unsigned i = 0; i < minionArray.size(); i++) {
minionArray.at(i).Update(dt);
}
}
void Alien::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
if(minionArray.size() > 0) {
for(unsigned i = 0; i < Alien::minionArray.size(); i++) {
minionArray.at(i).Render();
}
}
}
bool Alien::IsDead() {
return (Alien::hitpoints <= 0);
}
EDIT: the destructor of Alien was missing.
All classes derived from GameObject must define all pure virtual functions in GameObject. In your case, this is:
virtual void Update(float dt) = 0;
virtual void Render() = 0;
virtual bool IsDead() = 0;
Here is a similar question with more information. Hope this helps!
Related
This question already has answers here:
error: no matching function for call to 'begin(int*&)' c++
(3 answers)
Closed last month.
Here is my player class
#pragma once
#include <raylib.h>
#include "SpriteManager.h"
#include "Sprite.h"
#include "Utils.h"
#include "DashAbility.h"
#include "AbilityHolder.h"
class Player : public Sprite
{
public:
float moveSpeed = 300.0f;
DashAbility ability1;
AbilityHolder abilit1Holder;
void init(SpriteManager &spriteManager)
{
texture = spriteManager.player;
x = GetScreenWidth() / 2.0f;
y = GetScreenHeight() / 2.0f;
width = texture.width;
height = texture.height;
ability1.init(3.0f, 1.0f, 1000.0f);
abilit1Holder.init(ability1, KEY_E);
}
void update(Camera2D &camera)
{
vx = heldKeys(KEY_A, KEY_D) * moveSpeed;
vy = heldKeys(KEY_W, KEY_S) * moveSpeed;
if (vx > 0.0f)
fx = 1;
if (vx < 0.0f)
fx = -1;
abilit1Holder.update(this);
x += vx * GetFrameTime();
y += vy * GetFrameTime();
camera.target = (Vector2){x, y};
}
};
And here is my AbilityHolder class
#pragma once
#include <raylib.h>
#include "Ability.h"
class AbilityHolder
{
public:
int key;
float cooldownTimer = 0.0f;
float activeTimer = 0.0f;
bool isCooldown = false;
bool isActive = false;
Ability ability;
void init(Ability _ability, int _key)
{
ability = _ability;
key = _key;
}
void update(Sprite &target)
{
if (IsKeyPressed(key) && !isCooldown && !isActive)
{
isActive = true;
}
if (isActive)
{
ability.active(target);
activeTimer += GetFrameTime();
if (activeTimer > ability.activeTime)
{
isActive = false;
isCooldown = true;
activeTimer = 0.0f;
}
}
if (isCooldown)
{
cooldownTimer += GetFrameTime();
if (cooldownTimer > ability.cooldownTime)
{
isCooldown = false;
cooldownTimer = 0.0f;
}
}
}
};
Inside update function of Player class, I want to call ability1Holder update function and it takes 1 argument, and I put "this" inside it. But code blocks gives me this error:
include\Player.h|41|error: no matching function for call to
'AbilityHolder::update(Player*)'|
Try changing abilit1Holder.update(this); to abilit1Holder.update(*this);.
When building my C++ program, I'm getting the error message.
undefined reference to vtable
I have two virtual abstract classes called and I can't quite figure out what I'm doing wrong if I'm doing anything wrong.
I'm getting errors from both of the classes that are inheriting from the abstract class.
My abstract class is
undefined reference to `vtable for hittable_list'
undefined reference to `vtable for sphere'
hittable.h
#ifndef HITTABLE_H
#define HITTABLE_H
#include "ray.h"
struct hit_record {
hit_record() {}
~hit_record() {}
float t;
vecfloat p;
vecfloat normal;
float MAXFLOAT = 100.0;
};
//Abstract Class containing Sphere and hittablelist
class hittable
{
public:
virtual ~hittable() = 0;
virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const = 0;
};
#endif
Classes inherting from my abstract class are.
sphere.h
#ifndef SPHERE_H
#define SPHERE_H
#include "hittable.h"
class sphere : public hittable
{
public:
sphere() {}
~sphere() {}
sphere(vecfloat cen, float r) : center(cen), radius(r) {}
bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const;
protected:
vecfloat center;
float radius;
};
#endif
sphere.cc
#include "include/sphere.h"
bool sphere::hit(const ray &r, float t_min, float t_max, hit_record &rec) const
{
vecfloat oc = r.origin() - center;
float a = oc.dot_product(r.direction());
float b = oc.dot_product(oc) - radius * radius;
float c = oc.dot_product(oc) - radius * radius;
float discriminant = b * b - a * c;
if (discriminant > 0)
{
float temp = (-b - sqrt(b * b - a * c)) / a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.point_at_parameter(rec.t);
rec.normal = (rec.p - center) / radius;
return true;
}
temp = (-b + sqrt(b * b - a * c)) / a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.point_at_parameter(rec.t);
rec.normal = (rec.p - center) / radius;
return true;
}
}
return false;
}
hittable.h
#ifndef HITTABLELIST_H
#define HITTABLELIST_H
#include "hittable.h"
class hittable_list : public hittable
{
public:
hittable_list() {}
hittable_list(hittable **l, int n)
{
list = l;
list_size = n;
}
bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const;
~hittable_list() {}
protected:
hittable **list;
int list_size;
};
#endif
hittable.cc
#include "include/hittablelist.h"
bool hittable_list::hit(const ray &r, float t_min, float t_max, hit_record &rec) const
{
hit_record temp_rec;
auto hit_anything = false;
auto closet_so_far = t_max;
for (int i = 0; i < list_size; i++)
{
if (list[i]->hit(r, t_min, closet_so_far, temp_rec))
{
hit_anything = true;
closet_so_far = temp_rec.t;
rec = temp_rec;
}
}
return hit_anything;
}
Solution
Change
virtual ~hittable() = 0;
into
virtual ~hittable() = default;
or
virtual ~hittable()
{
// does nothing
}
The destructor can remain pure virtual, but it must have a definition.
hittable::~hittable()
{
// does nothing
}
So what happened?
We can crush the given code down to the following example (Note I can't reproduce the missing vtable with this code or the given code, but regardless, the above will fix it)
Minimal example:
class hittable
{
public:
virtual ~hittable() = 0; // here we have a destructor,
// but there's no implementation
// so there is nothing for the
// destructors of derived classes
// to call
virtual bool hit() const = 0;
};
class sphere: public hittable
{
public:
bool hit() const;
};
bool sphere::hit() const
{
return false;
}
destructors call any base class destructors, and when shpere goes to call ~hittable, it finds that while ~hittableis declared, there is no implementation. Nothing to call.
I have some code that when compiled, runs an Asteroid Game. I want to make some changes. In place of sprites for the ship, I would like to use trianges. For a bullet, I'd like to use a small rectangle, and finally, a polygon for the asteroids. The code uses an Entity Master Class with a list. Can somebody please elaborate on how to make these changes?
#include <SFML/Graphics.hpp>
#include <time.h>
#include <list>
using namespace sf;
const int W = 1200;
const int H = 800;
float DEGTORAD = 0.017453f;
class Animation
{
public:
float Frame, speed;
Sprite sprite;
std::vector<IntRect> frames;
Animation(){}
Animation (Texture &t, int x, int y, int w, int h, int count, float Speed)
{
Frame = 0;
speed = Speed;
for (int i=0;i<count;i++)
frames.push_back( IntRect(x+i*w, y, w, h) );
sprite.setTexture(t);
sprite.setOrigin(w/2,h/2);
sprite.setTextureRect(frames[0]);
}
void update()
{
Frame += speed;
int n = frames.size();
if (Frame >= n) Frame -= n;
if (n>0) sprite.setTextureRect( frames[int(Frame)] );
}
bool isEnd()
{
return Frame+speed>=frames.size();
}
};
class Entity
{
public:
float x,y,dx,dy,R,angle;
bool life;
std::string name;
Animation anim;
Entity()
{
life=1;
}
void settings(Animation &a,int X,int Y,float Angle=0,int radius=1)
{
anim = a;
x=X; y=Y;
angle = Angle;
R = radius;
}
virtual void update(){};
void draw(RenderWindow &app)
{
anim.sprite.setPosition(x,y);
anim.sprite.setRotation(angle+90);
app.draw(anim.sprite);
CircleShape circle(R);
circle.setFillColor(Color(255,0,0,170));
circle.setPosition(x,y);
circle.setOrigin(R,R);
//app.draw(circle);
}
virtual ~Entity(){};
};
class asteroid: public Entity
{
public:
asteroid()
{
dx=rand()%8-4;
dy=rand()%8-4;
name="asteroid";
}
void update()
{
x+=dx;
y+=dy;
if (x>W) x=0; if (x<0) x=W;
if (y>H) y=0; if (y<0) y=H;
}
};
class bullet: public Entity
{
public:
bullet()
{
name="bullet";
}
void update()
{
dx=cos(angle*DEGTORAD)*6;
dy=sin(angle*DEGTORAD)*6;
// angle+=rand()%7-3; /*try this*/
x+=dx;
y+=dy;
if (x>W || x<0 || y>H || y<0) life=0;
}
};
class player: public Entity
{
public:
bool thrust;
player()
{
name="player";
}
void update()
{
if (thrust)
{ dx+=cos(angle*DEGTORAD)*0.2;
dy+=sin(angle*DEGTORAD)*0.2; }
else
{ dx*=0.99;
dy*=0.99; }
int maxSpeed=15;
float speed = sqrt(dx*dx+dy*dy);
if (speed>maxSpeed)
{ dx *= maxSpeed/speed;
dy *= maxSpeed/speed; }
x+=dx;
y+=dy;
if (x>W) x=0; if (x<0) x=W;
if (y>H) y=0; if (y<0) y=H;
}
};
bool isCollide(Entity *a,Entity *b)
{
return (b->x - a->x)*(b->x - a->x)+
(b->y - a->y)*(b->y - a->y)<
(a->R + b->R)*(a->R + b->R);
}
int main()
{
srand(time(0));
RenderWindow app(VideoMode(W, H), "Asteroids!");
app.setFramerateLimit(60);
Texture t1,t2,t3,t4,t5,t6,t7;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
t3.loadFromFile("images/explosions/type_C.png");
t4.loadFromFile("images/rock.png");
t5.loadFromFile("images/fire_blue.png");
t6.loadFromFile("images/rock_small.png");
t7.loadFromFile("images/explosions/type_B.png");
t1.setSmooth(true);
t2.setSmooth(true);
Sprite background(t2);
Animation sExplosion(t3, 0,0,256,256, 48, 0.5);
Animation sRock(t4, 0,0,64,64, 16, 0.2);
Animation sRock_small(t6, 0,0,64,64, 16, 0.2);
Animation sBullet(t5, 0,0,32,64, 16, 0.8);
Animation sPlayer(t1, 40,0,40,40, 1, 0);
Animation sPlayer_go(t1, 40,40,40,40, 1, 0);
Animation sExplosion_ship(t7, 0,0,192,192, 64, 0.5);
std::list<Entity*> entities;
for(int i=0;i<15;i++)
{
asteroid *a = new asteroid();
a->settings(sRock, rand()%W, rand()%H, rand()%360, 25);
entities.push_back(a);
}
player *p = new player();
p->settings(sPlayer,200,200,0,20);
entities.push_back(p);
/////main loop/////
while (app.isOpen())
{
Event event;
while (app.pollEvent(event))
{
if (event.type == Event::Closed)
app.close();
if (event.type == Event::KeyPressed)
if (event.key.code == Keyboard::Space)
{
bullet *b = new bullet();
b->settings(sBullet,p->x,p->y,p->angle,10);
entities.push_back(b);
}
}
if (Keyboard::isKeyPressed(Keyboard::Right)) p->angle+=3;
if (Keyboard::isKeyPressed(Keyboard::Left)) p->angle-=3;
if (Keyboard::isKeyPressed(Keyboard::Up)) p->thrust=true;
else p->thrust=false;
for(auto a:entities)
for(auto b:entities)
{
if (a->name=="asteroid" && b->name=="bullet")
if ( isCollide(a,b) )
{
a->life=false;
b->life=false;
Entity *e = new Entity();
e->settings(sExplosion,a->x,a->y);
e->name="explosion";
entities.push_back(e);
for(int i=0;i<2;i++)
{
if (a->R==15) continue;
Entity *e = new asteroid();
e->settings(sRock_small,a->x,a->y,rand()%360,15);
entities.push_back(e);
}
}
if (a->name=="player" && b->name=="asteroid")
if ( isCollide(a,b) )
{
b->life=false;
Entity *e = new Entity();
e->settings(sExplosion_ship,a->x,a->y);
e->name="explosion";
entities.push_back(e);
p->settings(sPlayer,W/2,H/2,0,20);
p->dx=0; p->dy=0;
}
}
if (p->thrust) p->anim = sPlayer_go;
else p->anim = sPlayer;
for(auto e:entities)
if (e->name=="explosion")
if (e->anim.isEnd()) e->life=0;
if (rand()%150==0)
{
asteroid *a = new asteroid();
a->settings(sRock, 0,rand()%H, rand()%360, 25);
entities.push_back(a);
}
for(auto i=entities.begin();i!=entities.end();)
{
Entity *e = *i;
e->update();
e->anim.update();
if (e->life==false) {i=entities.erase(i); delete e;}
else i++;
}
//////draw//////
app.draw(background);
for(auto i:entities) i->draw(app);
app.display();
}
return 0;
}
it is not really relevant question to be asked here,
but take a look at this part of code:
Texture t1,t2,t3,t4,t5,t6,t7;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
t3.loadFromFile("images/explosions/type_C.png");
t4.loadFromFile("images/rock.png");
t5.loadFromFile("images/fire_blue.png");
t6.loadFromFile("images/rock_small.png");
t7.loadFromFile("images/explosions/type_B.png");
I am attempting to create a graphical representation of finite automata using xcode, and as such I have created classes for states and transitions. In order to make moving objects easy, I have included a collection of pointers of transitions going in and out of the state. Compiling is fines, but when I try to append to the vector, it produces the following error. EXC_BAD_ACCESS(code=1, address=0x3f35)
Following the error takes me to the std library, and shows the error being in this line.
template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
void
vector<_Tp, _Allocator>::push_back(const_reference __x)
{
if (this->__end_ != this->__end_cap())
{
__annotate_increase(1);
__alloc_traits::construct(this->__alloc(),
_VSTD::__to_raw_pointer(this->__end_), __x);
++this->__end_;
}
else
__push_back_slow_path(__x);
}
Here is a simplified version of my State class, my Transition class is declared before and is then defined afterwards.
class State
{
int id;
std::vector<Transition *> links_in;
std::vector<Transition *> links_out;
float x;
float y;
int r = radius; //x, y are centre coordinates of the circle representing the state, while r is the radius
bool is_active = false;
bool is_end = false;
bool is_shown = true;
bool is_moving;
public:
// Get Functions go here
// Set Functions go here
//Add functions
void add_in_trans(Transition * t){
links_in.push_back(t);
}
void add_out_trans(Transition * t){
links_out.push_back(t);
}
//Delete Functions
void remove_in_trans(){
links_in.pop_back();
}
void remove_out_trans(){
links_out.pop_back();
}
void draw_state();
State(int ix, int iy);
State(){}
}
If you have any suggestions for a better way of doing this, I am more then happy to hear them. I have spent all day trying to sort this out, to no avail.
Thanks in advance.
UPDATE:
I attempted to use integers and vectors as a temporary fix, but I came up with the same problem, so I assume that the problem isn't the pointers but the way I'm using vectors.
This is the code
#include <vector>
class Transition;
class State
{
int id;
std::vector<int> links_in;
std::vector<int> links_out;
float x;
float y;
int r = radius; //x, y are centre coordinates of the circle representing the state, while r is the radius
bool is_active = false;
bool is_end = false;
bool is_shown = true;
bool is_moving;
public:
// Get Functions
int get_x(){
return x;
}
int get_y(){
return y;
}
int get_id(){
return id;
}
bool is_it_active(){
return is_active;
}
bool is_it_moving(){
return is_moving;
}
bool is_in(int ix, int iy){ //Function to tell if pair of coordinates are in the circle, used to select.
std::cerr << ix-x << " " << iy-y << " " << r*r << std::endl;
if ((ix-x)*(ix-x) + (iy-y)*(iy-y) < r*r)
return true;
else
return false;
}
// Set Functions
void set_active(bool s){
is_active = s;
}
void set_moving(bool s){
is_moving = s;
}
void end_switch(){
is_end = !is_end;
}
void set_start(){
g_start_state = id;
}
void set_x(int ix){
x = ix;
}
void set_y(int iy){
y = iy;
}
//Add functions
void add_in_trans(int t){
links_in.push_back(t);
}
void add_out_trans(int t){
links_out.push_back(t);
}
//Delete Functions
void remove_in_trans(){
links_in.pop_back();
}
void remove_out_trans(){
links_out.pop_back();
}
void draw_state();
State(int ix, int iy);
State(){}
};
State::State(int ix, int iy){
id = g_state_num;
if (g_start_state == 0)
g_start_state = id;
x = ix;
y = iy;
}
void State::draw_state(){
if (is_shown){
if (is_moving)
glTranslatef(g_cursor_x, g_cursor_y, 0.0);
else
glTranslatef(x, y, 0.0);
fill_colour();
if (is_active)
active_fill_colour();
glBegin(GL_POLYGON);
for (size_t i=0; i<24; i++){
float n[2] = {static_cast<float>(r * cos(i*6)), static_cast<float>(r * sin(i*6))};
glVertex2fv(n);
}
glEnd();
line_colour();
glBegin(GL_LINES);
for (size_t i=0; i<24; i++){
float n[2] = {static_cast<float>(r * cos(i*6)), static_cast<float>(r * sin(i*6))};
glVertex2fv(n);
}
glEnd();
if(is_end){
glPushMatrix();
glScalef(0.9, 0.9, 0.9);
for (size_t i=0; i<24; i++){
float n[2] = {static_cast<float>(r * cos(i*6)), static_cast<float>(r * sin(i*6))};
glVertex2fv(n);
}
glPopMatrix();
}
text_colour();
std::string s = std::to_string(id);
for (int i=0; i<s.length(); i++){
glPushMatrix();
glTranslatef(-radius/2 + i*kerning, -radius/2, 0.0);
glScalef(0.3, 0.3, 1.0);
glutStrokeCharacter(GLUT_STROKE_ROMAN, s[i]);
glPopMatrix();
}
}
}
class Character{
int id;
char c;
public:
int get_id(){
return id;
}
char get_char(){
return c;
}
void set_char(char ic){
c = ic;
}
Character(char ic);
Character(){};
};
Character::Character(char ic){
id = g_character_num;
g_character_num++;
c = ic;
}
class Transition{
int ident;
State * from_state;
State * to_state;
float from[2];
float to[2];
Character c;
public:
void set_from(float x, float y){
from[0] = x;
from[1] = y;
}
void set_to(float x, float y){
to[0] = x;
to[1] = y;
}
void set_char(Character ic){
c = ic;
}
int get_id(){
return ident;
}
void draw_trans();
void set_trans(State * ifrom, State * ito, Character ic){
from_state = ifrom;
to_state = ito;
from[0] = ifrom->get_x();
from[1] = ifrom->get_y();
to[0] = ito->get_x();
to[1] = ito->get_y();
c = ic;
}
Transition(){};
Transition(State ifrom, State ito, Character ic){
from_state = &ifrom;
to_state = &ito;
from[0] = ifrom.get_x();
from[1] = ifrom.get_y();
to[0] = ito.get_x();
to[1] = ito.get_y();
c = ic;
}
};
void Transition::draw_trans(){
line_colour();
glBegin(GL_LINES);
glVertex2fv(from);
glVertex2fv(to);
glEnd();
float grad = (from[0] - to[0]) /(from[1] - to[1]); //(By finding the gradient of the slope, we can fin good place to show it's information, it's character.
if (grad < -1 || grad > 1){
glPushMatrix();
glTranslatef(from[0] - to[0] - 20, from[1] - to[1], 1.0);
}
else{
glPushMatrix();
glTranslatef(from[0] - to[0], from[1] - to[1] + 20, 1.0);
}
glutStrokeCharacter(GLUT_STROKE_ROMAN, (c.get_char()));
glPopMatrix();
}
LeftCollision in CheckCollision() goes true, when ever Object1 collides with Object2(square which is scrolling from right to left of screen) left side. But in the GameObject::Update()
Leftcollision never updates to True, though it changes to true in the CheckCollision section!!
What i want is, whenever the LeftCollision is true, Update should stop, until it becomes false again!!
Below is the code for Header file and CPP file!!
The problem is with LeftCollision updation!! Why is the value not reflected in the Update if condition!!
#pragma once
#include <iostream>
#include <allegro5/allegro5.h>
#include <allegro5/allegro_primitives.h>
#include "Globals.h"
class GameObject
{
private :
int ID;
bool alive;
bool collidable;
protected :
float velX;
float velY;
int dirX;
int dirY;
int boundX;
int boundY;
int maxFrame;
int curFrame;
int frameCount;
int frameDelay;
int frameWidth;
int frameHeight;
int animationColumns;
int animationDirection;
ALLEGRO_BITMAP *image;
public :
float x;
float y;
bool LeftCollision;
bool pause;
GameObject();
void virtual Destroy();
void Init(float x, float y, float velX, float velY, int dirX, int dirY, int boundX, int boundY);
void virtual Update();
void virtual Render();
float GetX() {return x;}
float GetY() {return y;}
void SetX(float x) {GameObject ::x = x;}
void SetY(float y) {GameObject ::y = y;}
int GetBoundX() {return boundX;}
int GetBoundY() {return boundY;}
int GetID() {return ID;}
void SetID(int ID) {GameObject::ID = ID;}
bool GetAlive() {return alive;}
void SetAlive(bool alive) {GameObject :: alive = alive;}
bool GetCollidable() {return collidable;}
void SetCollidable(bool collidable) {GameObject :: collidable = collidable;}
bool CheckCollisions(GameObject *otherObject);
void virtual Collided(int objectID);
bool Collidable();
};
#include "GameObject.h"
GameObject :: GameObject()
{
x = 0;
y = 0;
velX = 0;
velY = 0;
dirX = 0;
dirY = 0;
boundX = 0;
boundY = 0;
LeftCollision = false;
maxFrame = 0;
curFrame = 0;
frameCount = 0;
frameDelay = 0;
frameWidth = 0;
frameHeight = 0;
animationColumns = 0;
animationDirection = 0;
image = NULL;
alive = true;
collidable = true;
}
void GameObject :: Destroy()
{
}
void GameObject :: Init(float x, float y, float velX, float velY, int dirX, int dirY, int boundX, int boundY)
{
GameObject :: x = x;
GameObject :: y = y;
GameObject :: velX = velX;
GameObject :: velY = velY;
GameObject :: dirX = dirX;
GameObject :: dirY = dirY;
GameObject :: boundX = boundX;
GameObject :: boundY = boundY;
}
void GameObject :: Update()
{
if(LeftCollision == false)
{
x += velX * dirX;
y += velY * dirY;
}
}
void GameObject :: Render()
{
}
bool GameObject :: CheckCollisions(GameObject *otherObject)
{
float oX = otherObject->GetX();
float oY = otherObject->GetY();
int obX = otherObject->GetBoundX();
int obY = otherObject->GetBoundY();
if( x + boundX > oX - obX &&
x - boundX < oX + obX &&
y + boundY > oY - obY &&
y - boundY < oY + obY && otherObject->GetID() == TRIANGLE)
{
return true;
}
else if(((oX < x + boundX + 14)&&(oX+ 40 >x - boundX))&&!((oY < y + boundY)&&(oY+40 > y - boundY))
&& otherObject->GetID() == SQUARE)
{
y = oY - boundX - 10;
//x = oX + 40;
return true;
}
else if((oX < x + boundX + 14) && (oX > x - boundX) && otherObject->GetID() == SQUARE)
{
LeftCollision = true;
return false;
}
else
{
return false;
LeftCollision = false;
}
}
void GameObject :: Collided(int objectID)
{
}
bool GameObject :: Collidable()
{
return alive && collidable;
}
Is this part of your problem - returning without setting the value
else
{
return false;
LeftCollision = false;
}
The only thing that jumps to mind is that you've got more than one object going around and you're not always using the one you expect. Try putting something like:
printf("here(%s:%d) this=%p\n", __FILE__, __LINE__, this);
at the start of each method to make sure that the this point is what you think it is. The problem may lie in the calling code that you haven't shown.