I am trying to adopt the Marco Monster's Physics Demo (document: http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html and C reference code: https://github.com/spacejack/carphysics2d/blob/master/marco/Cardemo.c) in C++.
I ran into the problem that the car spins around itself and moves along the axis in an unpredictable manner (as it reacts to the input but does so unpredictably). I have spend the last 4 days trying to find the problem and got nothing. Please help as I am getting desperate with that. I have separated functionality of the car into separate classes (for better maintenance) and deduced that the problem occurs within the Wheel class and in Car class. Here is the code:
Wheel.h
class Wheel
{
public:
Wheel(const bool &isABSOn, const float &frontAxleToCG, const float &rearAxleToCG, const float &tireGripValue, const float &lockedTireGripCoef,
const float &lateralStiffnessFront, const float &lateralStiffnessRear, const float &brakeForceCoef, const float &ebrakeForceCoef,
const float &brakeTorque);
void SetValues(bool &isEbrakeOn, float &drivetrainTorque, float &steeringAngle, float &brakingInput,
float &frontAxleLoad, float &rearAxleLoad, float &surfaceCoefficient, float &angularVelocity, Vector2f &localVelocity);
void Update();
Vector2f GetSumForce();
float GetLateralTorque();
private:
bool m_IsEBrakeOn;
const bool m_IsABSOn;
float m_YawSpeed, m_VehicleAngularVelocity, m_VehicleRotationAngle, m_VehicleSideSlip, m_VehicleSlipAngleFrontAxle, m_VehicleSlipAngleRearAxle,
m_VehicleSteeringAngleRadInput,
m_SurfaceTypeGripCoefficient, m_DrivetrainTorqueNm, m_BrakingForceInputPercentage, m_FrontAxleLoad, m_RearAxleLoad;
const float m_CGtoFrontAxle, m_CGtoRearAxle, m_BaseTireGripValue, m_LockedTireGripCoefficent, m_LateralStiffnessFront,
m_LateralStiffnessRear, m_BreakForceCoefficent, m_EBrakeForceCoefficent, m_BrakeTorqueLimit, m_StableSpeedBoundary;
Vector2f m_LocalVehicleVelocity, m_VehicleLateralForceFront, m_VehicleLateralForceRear, m_VehicleLongtitudonalForceRear;
float FrontTireGripValue();
float RearTireGripValue();
float CombinedBrakingForceValueRearAxle();
};
Wheel.cpp
Wheel::Wheel(const bool &isABSOn, const float &frontAxleToCG, const float &rearAxleToCG, const float &tireGripValue, const float &lockedTireGripCoef,
const float &lateralStiffnessFront, const float &lateralStiffnessRear, const float &brakeForceCoef, const float &ebrakeForceCoef,
const float &brakeTorque)
: m_IsABSOn{ isABSOn }
, m_CGtoFrontAxle{ frontAxleToCG }
, m_CGtoRearAxle{ rearAxleToCG }
, m_BaseTireGripValue{ tireGripValue }
, m_LockedTireGripCoefficent{ lockedTireGripCoef }
, m_LateralStiffnessFront { lateralStiffnessFront }
, m_LateralStiffnessRear{ lateralStiffnessRear }
, m_BreakForceCoefficent{ brakeForceCoef }
, m_EBrakeForceCoefficent{ ebrakeForceCoef }
, m_BrakeTorqueLimit{ brakeTorque }
, m_StableSpeedBoundary{ 40.f } {}
void Wheel::Update()
{
if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
{
m_YawSpeed = 0.f;
}
else
{
m_YawSpeed = ((m_CGtoFrontAxle + m_CGtoRearAxle) / 2.f) * m_VehicleAngularVelocity;
}
if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
{
m_VehicleRotationAngle = 0.f;
}
else
{
m_VehicleRotationAngle = std::atan2(m_YawSpeed, m_LocalVehicleVelocity.x);
}
if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
{
m_VehicleSideSlip = 0.f;
}
else
{
m_VehicleSideSlip = std::atan2(m_LocalVehicleVelocity.y, m_LocalVehicleVelocity.x);
}
m_VehicleSlipAngleFrontAxle = m_VehicleSideSlip + m_VehicleRotationAngle - m_VehicleSteeringAngleRadInput;
m_VehicleSlipAngleRearAxle = m_VehicleSideSlip - m_VehicleRotationAngle;
m_VehicleLateralForceFront.x = 0.f;
m_VehicleLateralForceFront.y = m_LateralStiffnessFront * m_VehicleSlipAngleFrontAxle;
m_VehicleLateralForceFront.y = std::fminf(FrontTireGripValue(), m_VehicleLateralForceFront.y);
m_VehicleLateralForceFront.y = std::fmaxf(-FrontTireGripValue(), m_VehicleLateralForceFront.y);
m_VehicleLateralForceFront.y *= m_FrontAxleLoad;
m_VehicleLateralForceRear.x = 0.f;
m_VehicleLateralForceRear.y = m_LateralStiffnessRear * m_VehicleSlipAngleRearAxle;
m_VehicleLateralForceRear.y = std::fminf(RearTireGripValue(), m_VehicleLateralForceRear.y);
m_VehicleLateralForceRear.y = std::fmaxf(-RearTireGripValue(), m_VehicleLateralForceRear.y);
m_VehicleLateralForceRear.y *= m_RearAxleLoad;
m_VehicleLongtitudonalForceRear.x = m_SurfaceTypeGripCoefficient * (m_DrivetrainTorqueNm - (CombinedBrakingForceValueRearAxle() * utils::Sign(m_LocalVehicleVelocity.x)));
m_VehicleLongtitudonalForceRear.y = 0.f;
}
Vector2f Wheel::GetSumForce()
{
if (m_LocalVehicleVelocity.Length() < 1.0f && m_DrivetrainTorqueNm < 0.5f)
{
m_LocalVehicleVelocity.x = m_LocalVehicleVelocity.y = 0.f;
m_VehicleLateralForceFront.x = m_VehicleLateralForceFront.y = m_VehicleLateralForceRear.x = m_VehicleLateralForceRear.y = 0.f;
}
return Vector2f
{
m_VehicleLongtitudonalForceRear.x + std::sinf(m_VehicleSteeringAngleRadInput) * m_VehicleLateralForceFront.x + m_VehicleLateralForceRear.x,
m_VehicleLongtitudonalForceRear.y + std::cosf(m_VehicleSteeringAngleRadInput) * m_VehicleLateralForceFront.y + m_VehicleLateralForceRear.y
};
}
float Wheel::GetLateralTorque()
{
return m_CGtoFrontAxle * m_VehicleLateralForceFront.y - m_CGtoRearAxle * m_VehicleLateralForceRear.y;
}
void Wheel::SetValues(bool &isEbrakeOn, float &drivetrainTorque, float &steeringAngle, float &brakingInput,
float &frontAxleLoad, float &rearAxleLoad, float &surfaceCoefficient, float &angularVelocity, Vector2f &localVelocity)
{
m_IsEBrakeOn = isEbrakeOn;
m_DrivetrainTorqueNm = drivetrainTorque;
m_VehicleSteeringAngleRadInput = steeringAngle;
m_BrakingForceInputPercentage = brakingInput;
m_FrontAxleLoad = frontAxleLoad;
m_RearAxleLoad = rearAxleLoad;
m_SurfaceTypeGripCoefficient = surfaceCoefficient;
m_LocalVehicleVelocity = localVelocity;
m_VehicleAngularVelocity = angularVelocity;
}
float Wheel::CombinedBrakingForceValueRearAxle()
{
return (m_BrakeTorqueLimit * m_BrakingForceInputPercentage);
}
float Wheel::FrontTireGripValue()
{
return m_BaseTireGripValue * m_SurfaceTypeGripCoefficient;
}
float Wheel::RearTireGripValue()
{
if ((CombinedBrakingForceValueRearAxle() > m_DrivetrainTorqueNm) && (!m_IsABSOn) && (m_LocalVehicleVelocity.Length() > m_StableSpeedBoundary))
{
return m_BaseTireGripValue * m_LockedTireGripCoefficent * m_SurfaceTypeGripCoefficient;
}
else
{
return m_BaseTireGripValue * m_SurfaceTypeGripCoefficient;
}
}
Car.h
class Car
{
public:
Car(VehicleCfg *pVehicleSpecs);
InputControl *m_pThisSteeringAndPedals;
void Draw() const;
void Update(float &elapsedSec);
private:
bool m_NOSStatus, m_IsEBrakeOn;
int m_GearShifterInput;
float m_VehicleThrottleInpute, m_VehicleSteeringAngleRadInput, m_VehicleBrakeInput,
m_DrivetrainTorqueOutput, m_FrontAxleLoad, m_RearAxleLoad,
m_ElapsedSec, m_VehicleHeadingDirectionAngleRad, m_CSHeading, m_SNHeading,
m_VehicleRotationAngle, m_YawSpeed, m_VehicleAngularVelocity, m_VehicleSideSlip,
m_VehicleSlipAngleFrontAxle, m_VehicleSlipAngleRearAxle,
m_SurfaceCoefficent, m_AngularTorque, m_AngularAcceleration, m_VehicleHealthStatus;
const float m_FrontToCG, m_RearToCG, m_CarMass, m_Inertia, m_RollingResistance, m_DragCoefficient;
Point2f m_WorldVehicleCoordinate;
Vector2f m_LocalVehicleVelocity, m_WorldVehicleVelocity, m_VehicleLocalAcceleration, m_VehicleWorldAcceleration,
m_WheelForces, m_ResistanceForces, m_TotalForce;
Suspension *m_pThisSuspension;
Drivetrain *m_pThisDrivetrain;
Wheel *m_pThisWheel;
ModularRenderer *m_pThisVehicleDrawn;
};
Car.cpp
void Car::Update(float &elapsedSec)
{
m_ElapsedSec = elapsedSec;
m_GearShifterInput = m_pThisSteeringAndPedals->GetCurrentGearValue();
m_VehicleThrottleInpute = m_pThisSteeringAndPedals->GetCurrentThrottleValue(m_ElapsedSec, m_VehicleThrottleInpute);
m_VehicleSteeringAngleRadInput = m_pThisSteeringAndPedals->GetCurrentSteeringValue(m_ElapsedSec);
m_VehicleBrakeInput = m_pThisSteeringAndPedals->GetCurrrentBrakeValue(m_ElapsedSec);
m_NOSStatus = m_pThisSteeringAndPedals->GetIsNOSOnValue();
m_IsEBrakeOn = m_pThisSteeringAndPedals->GetIsEBrakeOnValue();
m_CSHeading = std::cosf(m_VehicleHeadingDirectionAngleRad);
m_SNHeading = std::sinf(m_VehicleHeadingDirectionAngleRad);
m_LocalVehicleVelocity.x = m_CSHeading * m_WorldVehicleVelocity.y + m_SNHeading * m_WorldVehicleVelocity.x;
m_LocalVehicleVelocity.y = -m_SNHeading * m_WorldVehicleVelocity.y + m_CSHeading * m_WorldVehicleVelocity.x;
m_pThisDrivetrain->SetValues(m_NOSStatus, m_GearShifterInput, m_VehicleThrottleInpute, m_LocalVehicleVelocity.Length());
m_DrivetrainTorqueOutput = m_pThisDrivetrain->GetDrivetrainOutput(m_ElapsedSec);
m_pThisSuspension->SetValues(m_VehicleLocalAcceleration, m_LocalVehicleVelocity.Length());
m_FrontAxleLoad = m_pThisSuspension->GetFrontAxleWeight();
m_RearAxleLoad = m_pThisSuspension->GetRearAxleWeight();
m_pThisWheel->SetValues(m_IsEBrakeOn, m_DrivetrainTorqueOutput, m_VehicleSteeringAngleRadInput, m_VehicleBrakeInput, m_FrontAxleLoad,
m_RearAxleLoad, m_SurfaceCoefficent, m_VehicleAngularVelocity, m_LocalVehicleVelocity);
m_pThisWheel->Update();
m_WheelForces = m_pThisWheel->GetSumForce();
m_AngularTorque = m_pThisWheel->GetLateralTorque();
m_ResistanceForces.x = -((m_RollingResistance * m_LocalVehicleVelocity.x) + (m_DragCoefficient * m_LocalVehicleVelocity.x * std::abs(m_LocalVehicleVelocity.x)));
m_ResistanceForces.y = -((m_RollingResistance * m_LocalVehicleVelocity.y) + (m_DragCoefficient * m_LocalVehicleVelocity.y * std::abs(m_LocalVehicleVelocity.y)));
m_TotalForce.x = m_WheelForces.x + m_ResistanceForces.x;
m_TotalForce.y = m_WheelForces.y + m_ResistanceForces.y;
m_VehicleLocalAcceleration.x = m_TotalForce.x / m_CarMass;
m_VehicleLocalAcceleration.y = m_TotalForce.y / m_CarMass;
if (m_WorldVehicleVelocity.Length() < 1.0f && m_VehicleThrottleInpute < 0.5f)
{
m_LocalVehicleVelocity.x = m_LocalVehicleVelocity.y = 0.f;
m_VehicleAngularVelocity = m_AngularTorque = m_AngularAcceleration = 0.f;
}
m_AngularAcceleration = m_AngularTorque / m_Inertia;
m_VehicleWorldAcceleration.x = m_CSHeading * m_VehicleLocalAcceleration.y + m_SNHeading * m_VehicleLocalAcceleration.x;
m_VehicleWorldAcceleration.y = -(m_SNHeading) * m_VehicleLocalAcceleration.y + m_CSHeading * m_VehicleLocalAcceleration.x;
m_WorldVehicleVelocity.x += m_ElapsedSec * m_VehicleWorldAcceleration.x;
m_WorldVehicleVelocity.y += m_ElapsedSec * m_VehicleWorldAcceleration.y;
m_WorldVehicleCoordinate.x += m_ElapsedSec * m_WorldVehicleVelocity.x;
m_WorldVehicleCoordinate.y += m_ElapsedSec * m_WorldVehicleVelocity.y;
std::cout << "m_WorldVehicleCoordinate: " << m_WorldVehicleCoordinate.x << ", " << m_WorldVehicleCoordinate.y << "\n";
m_VehicleAngularVelocity += m_ElapsedSec * m_AngularAcceleration;
m_VehicleHeadingDirectionAngleRad += m_ElapsedSec * m_VehicleAngularVelocity;
m_pThisVehicleDrawn->SetVariables(int(0), int(0), int(0), int(0), m_VehicleHeadingDirectionAngleRad, m_VehicleSteeringAngleRadInput, m_WorldVehicleCoordinate);
}
void Car::Draw() const
{
m_pThisVehicleDrawn->DrawTheVehicle();
}
I think that the error occurs due to some sort of singularity that occurs in the calculations but I fail to see where that occurs.
Since the car spins around, I looked at your use of angular velocity. The m_VehicleAngularVelocity value is not initialized in either class, so it has an indeterminate value. The only time it has a value set is in your check for the car being stopped.
The unpredictable motion is likely a similar problem.
You should initialize all your class members in a constructor to avoid those problems.
Why does Wheel::SetValues take all its parameters by reference? Since it is just copying them to internal variables, and they are basic types, just pass them in by value.
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 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!
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();
}
I have a derived class Circle of base class Shape, where each class has its own print, collide, merge, type, etc functions. I instantiate a bunch of Circle objects and put them into a container (its a container of pointers since I was running into trouble with object splicing). In this method I compare objects to each other and update properties. All of my derived member functions are called except for collide, which calls the base function. I print out the types of the objects before collide, and they are both circles. I have no idea why the derived collide is not being called like the other methods.
In the code directly below, the output to the type() methods are Circle.
The function where collide and other methods are called.
void calculateGravitationalAttractions(ShapeContainer &shapeContainer) {
double G = constants::gravitationalConstant;
double distance, diffX, diffY, tempAx, tempAy;
double Fnet; //Net Force on body
double theta; //Angle between two points in 2-D space
double accel; //Net acceleration of body
double distanceBetweencb, collisionDistance;
std::list<Shape*>::iterator ii;
std::list<Shape*>::iterator jj;
std::list<Shape*> container = shapeContainer.container;
//int callCount = 0;
for(ii = container.begin(); ii != container.end(); ++ii) {
tempAx = tempAy = 0;
for(jj = container.begin(); jj != container.end(); ++jj) {
if((*ii) != (*jj)) {
//callCount++;
(*ii)->type();
(*jj)->type();
if (!(*ii)->collide(*(*jj))) {
diffX = (*ii)->pos[0] - (*jj)->pos[0];
diffY = (*ii)->pos[1] - (*jj)->pos[1];
distance = sqrt((diffX * diffX) + (diffY * diffY));
Fnet = ((G * (*ii)->mass * (*jj)->mass)) / distance;
theta = atan2(diffY, diffX);
accel = Fnet / (*ii)->mass;
tempAx += -(accel * cos(theta));
tempAy += -(accel * sin(theta));
} else { //if they collide
if((*ii)->mass > (*jj)->mass) {
(*ii)->merge(*(*jj));
jj = container.erase(jj);
} else {
(*jj)->merge(*(*ii));
ii = container.erase(ii);
}
}
}
}
//printf("\n %f, %f, \n", tempAx, tempAy);
(*ii)->accel[0] = tempAx;
(*ii)->accel[1] = tempAy;
}
//printf("Container size is %d\n", container.size());
//printf("Callcount is %d\n\n", callCount);
}
My Shape and Circle classes.
typedef array<double, 2> Vector;
class Shape {
public:
Vector pos;
Vector vel;
Vector accel;
double mass;
bool move;
SDL_Color color;
Shape() {}
Shape(Vector Pos, Vector Vel, Vector Accel, double Mass, bool Move, SDL_Color Color) {
pos = Pos;
vel = Vel;
accel = Accel;
mass = Mass;
move = true;
color = Color;
}
virtual void print() {
printf("Type: Shape\n");
printf("xPos: %f, yPos: %f\n", pos[0], pos[1]);
printf("xVel: %f, yVel: %f\n", vel[0], vel[1]);
printf("xAccel: %f, yAccel: %f\n", accel[0], accel[1]);
printf("mass: %f\n\n", mass);
}
virtual void render(SDL_Renderer* renderer) {
//printf("Rendering shape.\n");
}
virtual bool collide(Shape &a) { //true if the shapes collide
printf("Checking collision of shape.\n");
double xDiff = pos[0] - a.pos[0];
double yDiff = pos[1] - a.pos[1];
if (sqrt((xDiff * xDiff) + (yDiff * yDiff) < 100)) {
return true;
} else {
return false;
}
}
virtual void merge(Shape &a) {
color.r = (color.r * mass + a.color.r * a.mass) / (mass + a.mass);
color.g = (color.g * mass + a.color.g * a.mass) / (mass + a.mass);
color.b = (color.b * mass + a.color.b * a.mass) / (mass + a.mass);
mass += a.mass;
printf("Merging shapes.");
}
virtual void type() {
cout << "Type: Shape\n";
}
};
class Circle: public Shape {
public:
double radius;
Circle() {}
Circle(Vector Pos, Vector Vel, Vector Accel, double Mass, bool Move, SDL_Color Color) {
pos = Pos;
vel = Vel;
accel = Accel;
mass = Mass;
radius = sqrt(mass) * constants::radiusFactor;
move = true;
color = Color;
}
void print() {
printf("Type: Circle\n");
printf("xPos: %f, yPos: %f\n", pos[0], pos[1]);
printf("xVel: %f, yVel: %f\n", vel[0], vel[1]);
printf("xAccel: %f, yAccel: %f\n", accel[0], accel[1]);
printf("mass: %f\n", mass);
printf("radius: %f\n\n", radius);
}
void render(SDL_Renderer* renderer) {
//printf("Rendering circle.\n");
int success = filledCircleRGBA(renderer, (int) pos[0], (int) pos[1],
(int) radius, color.r, color.g, color.b, 255);
}
bool collide(Circle &a) { //true if the shapes collide
printf("Checking collision of circle.\n");
double xDiff = pos[0] - a.pos[0];
double yDiff = pos[1] - a.pos[1];
if (sqrt((xDiff * xDiff) + (yDiff * yDiff) < radius + a.radius)) {
return true;
} else {
return false;
}
}
void merge(Circle &a) {
printf("Merging circles.");
//momentum calculations
double xVel = vel[0]*mass + a.vel[0]*a.mass;
double yVel = vel[1]*mass + a.vel[1]*a.mass;
double totalMass = mass + a.mass ;
vel[0] = xVel / mass * constants::frictionFactor;
vel[1] = yVel / mass * constants::frictionFactor;
//merge colors
color.r = (color.r * mass + a.color.r * a.mass) / (mass+a.mass);
color.g = (color.g * mass + a.color.g * a.mass) / (mass+a.mass);
color.b = (color.b * mass + a.color.b * a.mass) / (mass+a.mass);
mass += a.mass;
}
void type() {
cout << "Type: Circle\n";
}
All of my derived member functions are called except for collide
That would be because you don't actually override the collide method in your Circle subclass:
class Shape {
virtual bool collide(Shape &a) { ...
class Circle: public Shape {
bool collide(Circle &a) { ...
Different signature, different method.
What's wrong with this functions definitions? I've created this two functions and the second one calls the first one, so what i want is, depending on the if in the first one, the calling of AlignCamera(); will change what happens in AlignXAXis();
void AlignCamera();
{
double cx = ox+(0.5*(xmax-xmin))*sx;
double cy = oy+(0.5*(ymax-ymin))*sy;
double cz = oz+(0.5*(zmax-zmin))*sz;
int vx=0;
int vy=0;
int vz=0;
int nx=0;
int ny=0;
int nz=0;
int iaxis = current_widget->GetPlaneOrientation();
if (iaxis == 0)
{
vz = -1;
nx = ox + xmax*sx;
cx = ox + 256*sx;
}
else if (iaxis == 1)
{
vz = -1;
ny = oy + ymax*sy;
cy = oy + 512*sy;
}
else
{
vy = 1;
nz = oz +zmax*sz;
cz = oz + 64*sz;
}
int px = cx+nx*2;
int py = cy+ny*2;
int pz = cz+nz*3;
vtkCamera *camera=ren->GetActiveCamera();
camera->SetViewUp(vx, vy, vz);
camera->SetFocalPoint(cx, cy, cz);
camera->SetPosition(px, py, pz);
camera->OrthogonalizeViewUp();
ren->ResetCameraClippingRange();
renWin->Render();
}
// Define the action of AlignXAxis
void AlignXAxis();
{
int slice_number;
int po = planeX->GetPlaneOrientation();
if (po == 3)
{
planeX->SetPlaneOrientationToXAxes();
slice_number = (xmax-xmin)/2;
planeX->SetSliceIndex(slice_number);
}
else
{
slice_number = planeX->GetSliceIndex();
}
current_widget= planeX;
ui->horizontalScrollBar->setValue(slice_number);
ui->horizontalScrollBar->setMinimum(xmin);
ui->horizontalScrollBar->setMaximum(xmax);
AlignCamera();
}
the variables needed are defined before it, such as ox, oy, oz....
When i run it it says undefined reference to `AlignCamera()' or 'AlignXAxis()'.
void AlignCamera(); //This is merely a prototype, not a declaration.
Remove the Semicolon, or create a declaration afterwards.
void AlignCamera(); //Prototype
void AlignCamera() { //Declaration
//Do Stuff
}
The same applies for the other function. Remove that semicolon.
Remove the semicolons, so:
void AlignCamera();
{
...
}
becomes
void AlignCamera()
{
...
}