Calling pure virtual function on Box2D GetUserData's result - c++

First of all, I use Cocos2d-x-2.1.5 and Box2D 2.3.0 (not pretty sure how to check which exactly, but found that info on cocos' repository).
My problem appears when I try to call the pure virtual function from the object which was assigned to the b2Body object via SetUserData method.
I scheduled a method updateBodies to update sprites which are the part of my game object's representation.
void GameplayLogicLayer::updateBodies(float pDeltaTime)
{
mWorld->Step(pDeltaTime, 10, 10);
for(b2Body* tBodies = mWorld->GetBodyList(); tBodies; tBodies = tBodies->GetNext()){
A* tA = (static_cast<A*>(tBodies->GetUserData()));
if(tA != NULL)
{
tA->callPureVirtualFunction();
tA->callFunction();
}
}
}
The program crashes when it tries to execute callPureVirtualMethodFunction().
My hierarchy of objects is below (A contains mBody, which is b2Body type; B and C extends A):
In the constructors of B and C I create Box2D body and link the object to the b2Body by:
mBody = pWorld.CreateBody(&tBodyDef);
mBody->SetUserData(this);
Do you have an idea how it crashes while executing pure virtual function, but works well when I call methods from the base class?
EDIT - in response to LearnCocos2d user.
Here is the A class content.
#ifndef __A_H__
#define __A_H__
#include "cocos2d.h"
#include "Box2D/Box2D.h"
USING_NS_CC;
class A
{
public:
virtual void callPureVirtualFunction() = 0;
void callFunction();
protected:
CCSprite* mSprite;
b2Body* mBody;
b2Fixture* mFixture;
};
#endif // __A_H__
And C class implementation.
.h file:
#ifndef __C_H__
#define __C_H__
#include "A.h"
class C : public A
{
public:
C(CCLayer& pParent, b2World& pWorld, const char* pFileName, float pPositionX, float pPositionY, float pWidth, float pHeight);
C();
virtual void callPureVirtualFunction();
private:
bool mWithSensor;
};
#endif // __C_H__
.cpp file:
#include "C.h"
#include "../Utilities/Constants.h"
C::C(CCLayer& pParent, b2World& pWorld, const char* pFileName, float pPositionX, float pPositionY, float pWidth, float pHeight)
{
mWithSensor = false;
// GRAPHICS
if(pFileName)
{
mSprite = CCSprite::create(pFileName);
mSprite->setPosition(CCPointMake(pPositionX, pPositionY));
pParent.addChild(mSprite);
}
b2BodyDef tBodyDef;
tBodyDef.type = b2_kinematicBody;
tBodyDef.position.Set( pPositionX / PIXELS_IN_METER, pPositionY / PIXELS_IN_METER );
// tCollisionBoxBodyDef.userData = this;
tBodyDef.userData = NULL;
mBody = pWorld.CreateBody(&tBodyDef);
mBody->SetGravityScale(0.f);
mBody->SetUserData(this);
b2PolygonShape tBodyShape;
tBodyShape.SetAsBox(pWidth / 2.f / PIXELS_IN_METER, pHeight / 2.f / PIXELS_IN_METER);
b2FixtureDef tBodyFixtureDef;
tBodyFixtureDef.shape = &tBodyShape;
tBodyFixtureDef.friction = 0.4f;
tBodyFixtureDef.density = 10.0f;
tBodyFixtureDef.restitution = 0.1f;
mFixture = mBody->CreateFixture( &tBodyFixtureDef );
}
C::C()
{
}
/*virtual*/ void C::callPureVirtualFunction()
{
}

Related

EXCEPTION_ACCESS_VIOLATION when using RandomPointInBoundingBox method of KismetLibrary

I am facing an issue while generating a random point in a volume using KismetLibrary,
there is the code
#include "Spawner.h"
#include "Components/BoxComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "BaseCell.h"
// Sets default values
ASpawner::ASpawner()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
SpawningVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnVolumeBox"));
RootComponent = SpawningVolume;
Cell = ABaseCell::StaticClass();
}
// Called when the game starts or when spawned
void ASpawner::BeginPlay()
{
Super::BeginPlay();
SpawnCells();
}
// Called every frame
void ASpawner::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ASpawner::SpawnCells()
{
if(Cell != NULL)
{
UWorld* const World = GetWorld();
if (World) {
FVector Origin = SpawningVolume->Bounds.Origin;
FVector Extent = SpawningVolume->Bounds.BoxExtent;
FVector SpawnLocation = UKismetMathLibrary::RandomPointInBoundingBox(Origin, Extent);
FRotator SpawnRotation;
SpawnRotation.Pitch = FMath::FRand() * 360.0f;
SpawnRotation.Roll = FMath::FRand() * 360.0f;
SpawnRotation.Yaw = FMath::FRand() * 360.0f;
ABaseCell* SpawnedCell = World->SpawnActor<ABaseCell>(Cell, SpawnLocation, SpawnRotation);
}
}
}
I should be able to generate without using Kismet the random point but i thought if this kind of library exists we should use them...
it's throwing the following error: https://i.stack.imgur.com/6nG45.png
EDIT
when trying to debug i figured that actually it's when i'm accessing private property "SpawningVolume" that error is thrown... still can't figure why
here is the Spawner.h
#include "BaseCell.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Spawner.generated.h"
UCLASS()
class LIFE_API ASpawner : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ASpawner();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Spawnable
UPROPERTY(EditAnyWhere, category="Spawning")
TSubclassOf<class ABaseCell> Cell;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
private:
// SpawningVolume as BoxComponent
UPROPERTY(VisibleAnyWhere, category="Spawning", meta=(AllowPrivateAccess="true"))
class UBoxComponent* SpawningVolume;
void SpawnCells();
};
EDIT 2
Just added this condition and it seems that "SpawningVolume" is "nullptr" so i don't know what i'm doing wrong but i keep investigating
void ASpawner::SpawnCells()
{
if(Cell != NULL)
{
UWorld* const World = GetWorld();
if (World) {
// Added condition
if (SpawningVolume != nullptr) {
FVector Origin = SpawningVolume->Bounds.Origin;
FVector Extent = SpawningVolume->Bounds.BoxExtent;
FVector SpawnLocation = UKismetMathLibrary::RandomPointInBoundingBox(Origin, Extent);
FRotator SpawnRotation;
SpawnRotation.Pitch = FMath::FRand() * 360.0f;
SpawnRotation.Roll = FMath::FRand() * 360.0f;
SpawnRotation.Yaw = FMath::FRand() * 360.0f;
ABaseCell* SpawnedCell = World->SpawnActor<ABaseCell>(Cell, SpawnLocation, SpawnRotation);
}
}
}
}
ERROR
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x000000000000012c
UE4Editor_Life_0001!ASpawner::SpawnCells() [C:\Users\Benja\OneDrive\Documents\Unreal Projects\Life\Source\Life\Spawner.cpp:46]

(structname/classname) does not name a type C++

I have an issue with my structs and classes not having a "type"
My code looks like this, I will show for one error:
This my struct "intersection" declared under my "Vector" class in vector.h:
struct Intersection {
bool hasIntersection;
Shape *pShape;
float t;
Color color;
Intersection emptyIntersection();};
Then this is my include in Shape.cpp where I have a subclass structure with different shapes:
#include "../include/Shape.h"
This is one of the functions:
Intersection Sphere::intersect(const Ray &ray) {
// Sphere naar nul zetten
Ray localray = ray;
localray.origin -= centre;
Intersection localintersection{};
float a = localray.direction.length2();
float b = 2 * localray.direction.dot(localray.origin);
float c = localray.origin.length2() - sqr(radius);
float D = sqr(b) - 4 * a * c;
if (D < 0.0f){
return localintersection.emptyIntersection();
}
float t1 = (-b - std::sqrt(D)) / (2 * a);
float t2 = (-b + std::sqrt(D)) / (2 * a);
if (t1 > RAY_T_MIN && t1 < RAY_T_MAX) {
localintersection.hasIntersection = true;
localintersection.pShape = this;
localintersection.color = color;
localintersection.t = t1;
}
else if(t2 > RAY_T_MIN && t2 < RAY_T_MAX) {
localintersection.t = t2;
}
else{
return localintersection.emptyIntersection();
}}
And this is the top part of my Shape class in Shape.h
virtual Intersection intersect(const Ray& ray) = 0;
It is giving me the errors that 'Shape' does not name a type for my struct, and Intersection does not name a type for my Shape.h class. I do not know how to solve it, I have seen many other topics which have solutions, but none of these work
EDIT:
declaration of Shape and a subclass
class Shape {
public:
virtual Intersection intersect(const Ray& ray) = 0;
};
class Shapeset : public Shape{
protected:
std::vector<Shape*> shapes;
public:
Shapeset();
void addShape (Shape* shape);
virtual Intersection intersect(const Ray& ray);
};
Your header with Intersection declaration doesn't have Shape declaration.
Use code:
class Shape;
struct Intersection { ...
There is same trouble with Shape header: header doesn't have Intersection declaration.
I recommend you to include intersection header into shape header.

Access Violation Reading Location when assigning Float (0x0000000000000170)

I'm crashing with a Access Violation reading location. I'm doing this in Unreal Engine, but it's simple and I feel the issue should be universally applicable within C++, though I am new to it.
I am crashing when trying to assign LastDoorOpenTime in OpenDoor() of OpenDoor.cpp (below). I'm able assign to it successfully at the start of the program in UOpenDoor::BeginPlay(), but trying the same thing in OpenDoor() crashes the application with "Access Violation reading location".
OpenDoor.h:
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameFramework/Actor.h"
#include "Engine/TriggerVolume.h"
#include "Engine/World.h"
#include "OpenDoor.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ESCAPEROOM_API UOpenDoor : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UOpenDoor();
protected:
// Called when the game starts
virtual void BeginPlay() override;
void OpenDoor();
void CloseDoor();
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
UPROPERTY(VisibleAnywhere)
float OpenAngle = -60.f;
UPROPERTY(EditAnywhere)
ATriggerVolume* PressurePlate;
UPROPERTY(EditAnywhere)
float DoorCloseDelay = 1.f;
float LastDoorOpenTime;
AActor* ActorThatOpens;
AActor* Owner;
bool IsDoorOpen;
UWorld* ThisWorld;
};
OpenDoor.cpp:
#include "OpenDoor.h"
// Sets default values for this component's properties
UOpenDoor::UOpenDoor()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
// ...
}
// Called when the game starts
void UOpenDoor::BeginPlay()
{
Super::BeginPlay();
ThisWorld = GetWorld();
ActorThatOpens = ThisWorld->GetFirstPlayerController()->GetPawn();
AActor* Owner = GetOwner();
IsDoorOpen = false;
}
void UOpenDoor::OpenDoor()
{
Owner->SetActorRotation(FRotator(0.f, OpenAngle, 0.f));
int cow = 1 + 1;
LastDoorOpenTime = 0.f; //ACCESS VIOLATION HERE
IsDoorOpen = true;
}
void UOpenDoor::CloseDoor()
{
Owner->SetActorRotation(FRotator(0.f, 0.f, 0.f));
IsDoorOpen = false;
}
// Called every frame
void UOpenDoor::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (PressurePlate->IsOverlappingActor(ActorThatOpens)) {
OpenDoor();
}
if (IsDoorOpen) {
if (ThisWorld->GetTimeSeconds() >= LastDoorOpenTime + DoorCloseDelay) {
CloseDoor();
}
}
}
Changing: "AActor* Owner = GetOwner();" to "Owner = GetOwner();" fixed it.

Cocos2d retain() in inherited classes

So I've had a lot of trouble with Cocos2d's auto-release shenanigans, and (almost) wish that I could just handle all of that myself...
Anyways, the problem I've had is with creating some animations. I've got a class called AnimatedDamageableSprite which inherits from DamageableSprite which inherits from Sprite which inherits from CCSprite etc...
When I create an AnimatedDamageableSprite, I have a successful animation on the screen, which runs as it should.
When I create a Suicider, which (you guessed it) inherits from AnimatedDamageableSprite, the CCArray which contains the frames for animation doesn't survive beyond the first loop, and on the second update attempt, the program gets an AV error.
Here's the code for the two classes:
Sprite.h
// This class works
class AnimatedDamageableSprite :public DamageableSprite {
public:
AnimatedDamageableSprite(int hp, CCPoint pos, CCTexture2D* tex, int rows, int columns, float scaleX, float scaleY);
virtual ~AnimatedDamageableSprite();
virtual void update(float dt);
virtual bool updateFrame(float dt);
virtual SpriteType getType() { return ANIMATED_DAMAGEABLE_SPRITE; };
protected:
float m_frameNum;
CCArray* m_frames;
int m_numOfFrames;
};
// This class doesn't
class Suicider :public AnimatedDamageableSprite {
public:
Suicider(int difficulty);
virtual ~Suicider();
virtual void update(float dt);
virtual SpriteType getType() { return SUICIDER; };
private:
float m_speed;
};
Sprite.cpp
AnimatedDamageableSprite::AnimatedDamageableSprite(int hp, CCPoint pos, CCTexture2D* tex, int rows, int columns, float scaleX, float scaleY)
:DamageableSprite(hp, pos, tex, scaleX, scaleY), m_frameNum(0), m_numOfFrames(rows*columns) {
float texWidth = tex->getContentSize().width / (float)columns;
float texHeight = tex->getContentSize().height / (float)rows;
m_frames = CCArray::createWithCapacity(m_numOfFrames);
m_frames->retain();
for (unsigned int i = 0; i < columns; i++) {
for (unsigned int j = 0; j < rows; j++) {
CCRect r(i*texWidth, j*texHeight, texWidth, texHeight);
m_frames->addObject(new CCSpriteFrame);
((CCSpriteFrame*)m_frames->lastObject())->createWithTexture(tex, r);
((CCSpriteFrame*)m_frames->lastObject())->initWithTexture(tex, r);
m_frames->lastObject()->retain();
}
}
initWithSpriteFrame((CCSpriteFrame*)m_frames->objectAtIndex(m_frameNum));
setTexture(tex);
setPosition(pos);
setScaleX(scaleX);
setScaleY(scaleY);
updateTransform();
}
// This function is called every frame. It returns a boolean for unrelated reasons
bool AnimatedDamageableSprite::updateFrame(float dt) {
bool retVal = false;
// Assume animations are at 30 FPS for now
m_frameNum += dt * 0.03f;
while (m_frameNum >= m_numOfFrames) {
m_frameNum -= m_numOfFrames;
retVal = true;
}
setDisplayFrame((CCSpriteFrame*)m_frames->objectAtIndex(m_frameNum));
updateTransform();
return retVal;
}
// This class calls the constructor of the one that works, and does nothing else relevant to the problem
// It also doesn't override the updateImage() function
Suicider::Suicider(int difficulty)
: AnimatedDamageableSprite(1, CCPoint(10,10), g_textureManager.getTexture("Suicider Sheet"), 6, 10, SCALE_WIDTH, SCALE_HEIGHT) {
// ...
}
EDIT:
Seems I forgot to actually point out the problem.
The CCArray* m_frames declared in AnimatedDamageableSprite is fine when used in that instance, but it is deleted at the end of a frame when used in the Suicider class - i.e. it isn't being retained. Hence the AV error when I try to access an item inside it which no-longer exists
I tried retaining it in the Suicider constructor as well, although that didn't change anything.

How to create an object inside another class with a constructor?

So I was working on my code, which is designed in a modular way. Now, one of my classes; called Splash has to create a object of another class which is called Emitter. Normally you would just create the object and be done with it, but that doesn't work here, as the Emitter class has a custom constructor. But when I try to create an object, it doesn't work.
As an example;
Emitter has a constructor like so: Emitter::Emitter(int x, int y, int amount); and needs to be created so it can be accessed in the Splash class.
I tried to do this, but it didn't work:
class Splash{
private:
Emitter ps(100, 200, 400, "firstimage.png", "secondimage.png"); // Try to create object, doesn't work.
public:
// Other splash class functions.
}
I also tried this, which didn't work either:
class Splash{
private:
Emitter ps; // Try to create object, doesn't work.
public:
Splash() : ps(100, 200, 400, "firstimage.png", "secondimage.png")
{};
}
Edit: I know the second way is supposed to work, however it doesn't. If I remove the Emitter Section, the code works. but when I do it the second way, no window opens, no application is executed.
So how can I create my Emitter object for use in Splash?
Edit:
Here is my code for the emitter class and header:
Header
// Particle engine for the project
#ifndef _PARTICLE_H_
#define _PARTICLE_H_
#include <vector>
#include <string>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "image.h"
extern SDL_Surface* gameScreen;
class Particle{
private: // Particle settings
int x, y;
int lifetime;
private: // Particle surface that shall be applied
SDL_Surface* particleScreen;
public: // Constructor and destructor
Particle(int xA, int yA, string particleSprite);
~Particle(){};
public: // Various functions
void show();
bool isDead();
};
class Emitter{
private: // Emitter settings
int x, y;
int xVel, yVel;
private: // The particles for a dot
vector<Particle> particles;
SDL_Surface* emitterScreen;
string particleImg;
public: // Constructor and destructor
Emitter(int amount, int x, int y, string particleImage, string emitterImage);
~Emitter();
public: // Helper functions
void move();
void show();
void showParticles();
};
#endif
and here is the emitter functions:
#include "particle.h"
// The particle class stuff
Particle::Particle(int xA, int yA, string particleSprite){
// Draw the particle in a random location about the emitter within 25 pixels
x = xA - 5 + (rand() % 25);
y = yA - 5 + (rand() % 25);
lifetime = rand() % 6;
particleScreen = Image::loadImage(particleSprite);
}
void Particle::show(){
// Apply surface and age particle
Image::applySurface(x, y, particleScreen, gameScreen);
++lifetime;
}
bool Particle::isDead(){
if(lifetime > 11)
return true;
return false;
}
// The emitter class stuff
Emitter::Emitter(int amount, int x, int y, string particleImage, string emitterImage){
// Seed the time for random emitter
srand(SDL_GetTicks());
// Set up the variables and create the particles
x = y = xVel = yVel = 0;
particles.resize(amount, Particle(x, y, particleImage));
emitterScreen = Image::loadImage(emitterImage);
particleImg = particleImage;
}
Emitter::~Emitter(){
particles.clear();
}
void Emitter::move(){
}
void Emitter::show(){
// Show the dot image.
Image::applySurface(x, y, emitterScreen, gameScreen);
}
void Emitter::showParticles(){
// Go through all the particles
for(vector<Particle>::size_type i = 0; i != particles.size(); i++){
if(particles[i].isDead() == true){
particles.erase(particles.begin() + i);
particles.insert(particles.begin() + i, Particle(x, y, particleImg));
}
}
// And show all the particles
for(vector<Particle>::size_type i = 0; i != particles.size(); i++){
particles[i].show();
}
}
Also here is the Splash Class and the Splash Header.
The second option should work, and I would start looking at compilation errors to see why it doesn't. In fact, please post any compilation errors you have related to this code.
In the meantime, you can do something like this:
class Splash{
private:
Emitter* ps;
public:
Splash() { ps = new Emitter(100,200,400); }
Splash(const Splash& copy_from_me) { //you are now responsible for this }
Splash & operator= (const Splash & other) { //you are now responsible for this}
~Splash() { delete ps; }
};
Well, I managed to fix it, in a hackish way though. What I did was create a default constructor, and move my normal Constructor code into a new function. Then I created the object and called the the new init function to set everything up.