I followed the popular tutorials on skeletal animation by Thin Matrix and another code sample on
GitHub
The mesh renders find without any animations. But as soon as animations are applied it gets skewed.
If I pass identity matrices as bonetransforms, it works. Works as in it still renders properly just without any animation.
Also I noticed that the collada file I use uses Z as up and I use Y as up. But I export all data without changing a thing to make sure all transforms and vertex data work as intended. I later on plan on adjusting this as I export so that the data uses Y as up as well.
Here's my code for Skeletal Animation:
Header:
class SkeletalAnimation {
typedef struct Bone{
int id;
std::string name;
glm::mat4 offset;
std::vector<Bone> children;
} Bone;
typedef struct {
std::vector<float> translationTimestamps;
std::vector<float> rotationTimetamps;
std::vector<float> scalingTimetamps;
std::vector<glm::vec3> translations;
std::vector<glm::quat> rotations;
std::vector<glm::vec3> scalings;
} BoneTransforms;
typedef struct Animation {
float duration;
float ticksPerSecond;
std::unordered_map<std::string, BoneTransforms> boneTransforms;
Animation(float pDuration, float ticksPerSecond) :
duration(pDuration),
ticksPerSecond(ticksPerSecond),
boneTransforms({})
{}
Animation() {}
} Animation;
typedef std::unordered_map<std::string, std::pair<int, glm::mat4>> BoneData;
typedef std::unordered_map<std::string, Animation> AnimationMap;
typedef std::vector<glm::mat4> Pose;
typedef struct{
unsigned int segment;
float fracture;
} Segment;
typedef struct {
Pose pose;
BoneData boneData;
unsigned int boneCount;
std::string name;
Bone skeleton;
} MeshEntry;
typedef std::unordered_map<std::string, MeshEntry> MeshBoneMap;
private:
const std::string mPath;
SDL_Renderer* mRenderer;
std::vector<MeshEntry> mMeshEntries;
std::vector<SkeletalMesh*> mMeshes;
std::vector<ImageTexture*> mTextures;
std::vector<unsigned int> mMeshToTexture;
std::string* mCurrentAnimation;
std::vector<std::string> mAnimations;
AnimationMap mAnimationMap;
Segment mCurrentSegment;
glm::mat4 mGlobalInverseTransform;
MeshBoneMap mMeshBoneMap;
static glm::mat4 sIdentityMatrix;
void LoadNode(aiNode* pNode, const aiScene* pScene);
void LoadSkeletalMesh(aiMesh* pMesh, const aiScene* pScene);
bool LoadBones(Bone& pBone, aiNode* pNode, BoneData& pBoneData);
void LoadAnimations(const aiScene* pScene);
void LoadMaterials(const aiScene* pScene);
void Animate(float pDeltaTime, Bone& pSkeleton, Pose& pPose, glm::mat4& pParentTransform);
static inline glm::mat4 aiToGlmMat4(const aiMatrix4x4& pAiMat);
static inline glm::vec3 aiToGlmVec3(const aiVector3D& pAiVec);
static inline glm::quat aiToGlmQuat(const aiQuaternion& pAiVec);
static inline void GetSegment(Segment* pSegment,const std::vector<float>& pTimestamps,const float pDeltaTime);
public:
SkeletalAnimation(const std::string pPath, SDL_Renderer* pRenderer);
~SkeletalAnimation();
void LoadAnimation();
void GetAllAnimations(std::vector<std::string>* pAnimations);
float GetAnimationDuration();
void SetAnimationTime(float pTime);
void SetAnimation(std::string pAnimation);
void RenderAnimation(float pDeltaTime, SkeletalAnimationShader* pSkeletalAnimationShader);
void RenderStill(SkeletalAnimationShader* pSkeletalAnimationShader);
void ClearModel();
};
Source:
glm::mat4 SkeletalAnimation::sIdentityMatrix = glm::mat4();
SkeletalAnimation::SkeletalAnimation(const std::string pPath, SDL_Renderer* pRenderer) :
mPath(pPath),
mRenderer(pRenderer),
mCurrentAnimation(new std::string()),
mAnimations({}),
mAnimationMap({}),
mMeshBoneMap({})
{}
SkeletalAnimation::~SkeletalAnimation() {
}
void SkeletalAnimation::LoadAnimation() {
Assimp::Importer _importer;
const aiScene* _scene = _importer.ReadFile(mPath, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices);
if (!_scene) {
SDL_Log("Assimp Error Loading Animation at path: %s \n Error: %s .", mPath.c_str(), _importer.GetErrorString());
return;
}
mGlobalInverseTransform = glm::inverse(aiToGlmMat4(_scene->mRootNode->mTransformation));
LoadNode(_scene->mRootNode, _scene);
LoadAnimations(_scene);
LoadMaterials(_scene);
}
void SkeletalAnimation::LoadNode(aiNode* pNode, const aiScene* pScene) {
for (size_t i = 0; i < pNode->mNumMeshes; i++) {
LoadSkeletalMesh(pScene->mMeshes[pNode->mMeshes[i]], pScene);
}
for (size_t i = 0; i < pNode->mNumChildren; i++) {
LoadNode(pNode->mChildren[i], pScene);
}
}
void SkeletalAnimation::LoadSkeletalMesh(aiMesh* pMesh, const aiScene* pScene) {
MeshEntry _meshEntry;
_meshEntry.boneCount = pMesh->mNumBones;
_meshEntry.name = std::string(pMesh->mName.C_Str());
_meshEntry.pose = {};
_meshEntry.pose.resize(pMesh->mNumBones, sIdentityMatrix);
_meshEntry.boneData = {};
SkeletalMeshData _meshData;
for (size_t i = 0; i < pMesh->mNumVertices; i++) {
_meshData.vertices.insert(_meshData.vertices.end(),
{
pMesh->mVertices[i].x,
pMesh->mVertices[i].y , //Swaped Y and Z since Blender uses Z as up and I use Y as up.
pMesh->mVertices[i].z });
if (pMesh->mTextureCoords[0]) {
_meshData.uvs.insert(_meshData.uvs.end(),
{
pMesh->mTextureCoords[0][i].x,
pMesh->mTextureCoords[0][i].y
});
}
else {
_meshData.uvs.insert(_meshData.uvs.end(),
{
0.0f,
0.0f
});
}
_meshData.normals.insert(_meshData.normals.end(),
{
pMesh->mNormals[i].x,
pMesh->mNormals[i].y ,
pMesh->mNormals[i].z });
_meshData.boneIDs.insert(_meshData.boneIDs.end(), {
0,
0,
0,
0});
_meshData.weights.insert(_meshData.weights.end(), {
0.0f,
0.0f,
0.0f,
0.0f});
}
for (size_t i = 0; i < pMesh->mNumFaces; i++) {
aiFace _face = pMesh->mFaces[i];
for (size_t j = 0; j < _face.mNumIndices; j++) {
_meshData.indices.push_back(_face.mIndices[j]);
}
}
for (size_t i = 0; i < pMesh->mNumBones; i++) {
aiBone* _bone = pMesh->mBones[i];
glm::mat4 _offset = aiToGlmMat4(_bone->mOffsetMatrix);
_meshEntry.boneData[_bone->mName.C_Str()] = std::make_pair(i , _offset);
for (size_t j = 0; j < _bone->mNumWeights; j++) {
aiVertexWeight _weight = _bone->mWeights[j];
unsigned int _vertexID = _weight.mVertexId * 4;
for (size_t k = 0; k < 4; k++) {
if (_meshData.weights[_vertexID + k] == 0.0f) {
_meshData.weights[_vertexID + k] = _weight.mWeight;
_meshData.boneIDs[_vertexID + k] = i;
break;
}
}
}
}
for (size_t i = 0; i < _meshData.weights.size(); i+=4) {
float _totalWeight =
_meshData.weights[i] +
_meshData.weights[i+1] +
_meshData.weights[i+2] +
_meshData.weights[i+3];
if (_totalWeight > 0.0f) {
_meshData.weights[i] /= _totalWeight;
_meshData.weights[i+1] /= _totalWeight;
_meshData.weights[i+2] /= _totalWeight;
_meshData.weights[i+3] /= _totalWeight;
}
}
SkeletalMesh* _newMesh = new SkeletalMesh();
_newMesh->BuildMesh(_meshData);
mMeshes.push_back(_newMesh);
mMeshToTexture.push_back(pMesh->mMaterialIndex);
LoadBones(_meshEntry.skeleton, pScene->mRootNode, _meshEntry.boneData);
mMeshEntries.push_back(_meshEntry);
}
bool SkeletalAnimation::LoadBones(Bone& pBone ,aiNode* pNode, BoneData& pBoneData) {
if (pBoneData.find(pNode->mName.C_Str()) != pBoneData.end()) {
pBone.name = pNode->mName.C_Str();
pBone.id = pBoneData[pBone.name].first;
pBone.offset = pBoneData[pBone.name].second;
for (size_t i = 0; i < pNode->mNumChildren; i++) {
Bone _child;
LoadBones(_child, pNode->mChildren[i], pBoneData);
pBone.children.push_back(_child);
}
return true;
}
else {
for (size_t i = 0; i < pNode->mNumChildren; i++) {
if (LoadBones(pBone, pNode->mChildren[i], pBoneData)) {
return true;
}
}
}
return false;
}
void SkeletalAnimation::LoadAnimations(const aiScene* pScene) {
for (size_t i = 0; i < pScene->mNumAnimations; i++) {
Animation _currentInternalAnimation(0.0f, 1.0f);
aiAnimation* _currentAiAnimation = pScene->mAnimations[i];
mAnimations.push_back(std::string(_currentAiAnimation->mName.C_Str()));
if (i == 0) {
*mCurrentAnimation = mAnimations[0];
}
if (_currentAiAnimation->mTicksPerSecond != 0.0f) {
_currentInternalAnimation.ticksPerSecond = _currentAiAnimation->mTicksPerSecond;
}
else {
_currentInternalAnimation.ticksPerSecond = 1;
}
_currentInternalAnimation.duration = _currentAiAnimation->mDuration * _currentAiAnimation->mTicksPerSecond;
_currentInternalAnimation.boneTransforms = {};
BoneTransforms _transforms;
for (size_t j = 0; j < _currentAiAnimation->mNumChannels; j++) {
aiNodeAnim* _channel = _currentAiAnimation->mChannels[j];
for (size_t k = 0; k < _channel->mNumPositionKeys; k++) {
_transforms.translations.push_back(aiToGlmVec3(_channel->mPositionKeys[k].mValue));
_transforms.translationTimestamps.push_back(_channel->mPositionKeys[k].mTime);
}
for (size_t k = 0; k < _channel->mNumRotationKeys; k++) {
_transforms.rotations.push_back(aiToGlmQuat(_channel->mRotationKeys[k].mValue));
_transforms.rotationTimetamps.push_back(_channel->mRotationKeys[k].mTime);
}
for (size_t k = 0; k < _channel->mNumScalingKeys; k++) {
_transforms.scalings.push_back(aiToGlmVec3(_channel->mScalingKeys[k].mValue));
_transforms.scalingTimetamps.push_back(_channel->mScalingKeys[k].mTime);
}
_currentInternalAnimation.boneTransforms[_channel->mNodeName.C_Str()] = _transforms;
}
mAnimationMap[_currentAiAnimation->mName.C_Str()] = _currentInternalAnimation;
}
}
void SkeletalAnimation::LoadMaterials(const aiScene* pScene) {
mTextures.resize(pScene->mNumMaterials);
for (size_t i = 0; i < pScene->mNumMaterials; i++) {
aiMaterial* _material = pScene->mMaterials[i];
mTextures[i] = nullptr;
if (_material->GetTextureCount(aiTextureType_DIFFUSE)) {
aiString _path;
if (_material->GetTexture(aiTextureType_DIFFUSE, 0, &_path) == AI_SUCCESS) {
int _idx = std::string(_path.data).rfind("\\");
std::string _fileName = std::string(_path.data).substr(_idx + 1);
std::string _texturePath = std::string("assets/") + _fileName;
SDL_Log("Model Loading Texture at path: %s .", _texturePath.c_str());
mTextures[i] = new ImageTexture(_texturePath, mRenderer);
mTextures[i]->Load();
if (!mTextures[i]->IsLoaded()) {
delete mTextures[i];
mTextures[i] = nullptr;
SDL_Log("Model Error Loading Texture at path: %s .", _texturePath.c_str());
}
}
}
}
}
float SkeletalAnimation::GetAnimationDuration() {
return mAnimationMap[*mCurrentAnimation].duration;
}
void SkeletalAnimation::SetAnimationTime(float pTime) {
for (size_t i = 0; i < mMeshes.size(); i++) {
MeshEntry& _entry = mMeshEntries[i];
Animate(pTime, _entry.skeleton, _entry.pose, sIdentityMatrix);
}
}
void SkeletalAnimation::Animate(float pDeltaTime, Bone& pSkeleton, Pose& pPose, glm::mat4& pParentTransform) {
Animation& _currentAnimation = mAnimationMap[*mCurrentAnimation];
BoneTransforms& _boneTransforms = _currentAnimation.boneTransforms[pSkeleton.name];
pDeltaTime = fmod(pDeltaTime, _currentAnimation.duration);
//Calculate translations
GetSegment(&mCurrentSegment, _boneTransforms.translationTimestamps, pDeltaTime);
glm::vec3 _translation = glm::mix(
_boneTransforms.translations[mCurrentSegment.segment - 1],
_boneTransforms.translations[mCurrentSegment.segment],
mCurrentSegment.fracture);
//Calculate rotations
GetSegment(&mCurrentSegment, _boneTransforms.rotationTimetamps, pDeltaTime);
glm::quat _rotation = glm::slerp(
_boneTransforms.rotations[mCurrentSegment.segment - 1],
_boneTransforms.rotations[mCurrentSegment.segment],
mCurrentSegment.fracture);
//Calculate scalings
GetSegment(&mCurrentSegment, _boneTransforms.scalingTimetamps, pDeltaTime);
glm::vec3 _scaling = glm::mix(
_boneTransforms.scalings[mCurrentSegment.segment - 1],
_boneTransforms.scalings[mCurrentSegment.segment],
mCurrentSegment.fracture);
glm::mat4 _translationMatrix = glm::translate(glm::mat4(1.0f), _translation);
glm::mat4 _rotationMatrix = glm::toMat4(_rotation);
glm::mat4 _scalingMatrix = glm::scale(glm::mat4(1.0f), _scaling); glm::mat4(1.0f);
glm::mat4 _localTransform = _translationMatrix * _rotationMatrix * _scalingMatrix;
glm::mat4 _globalTransform = pParentTransform * _localTransform;
pPose[pSkeleton.id] = mGlobalInverseTransform * _globalTransform * pSkeleton.offset;
for (Bone& _child : pSkeleton.children) {
Animate(pDeltaTime, _child, pPose, _globalTransform);
}
}
void SkeletalAnimation::GetAllAnimations(std::vector<std::string>* pAnimations) {
pAnimations->clear();
*pAnimations = mAnimations;
}
void SkeletalAnimation::SetAnimation(std::string pAnimation) {
assert(std::find(mAnimations.begin(), mAnimations.end(), pAnimation) != mAnimations.end(), "Animation does not exist.");
*mCurrentAnimation = pAnimation;
}
void SkeletalAnimation::RenderAnimation(float pDeltaTime, SkeletalAnimationShader* pSkeletalAnimationShader) {
for (size_t i = 0; i < mMeshes.size(); i++) {
unsigned int _materialIndex = mMeshToTexture[i];
if (_materialIndex < mTextures.size() && mTextures[_materialIndex]) {
mTextures[_materialIndex]->Enable();
}
MeshEntry& _entry = mMeshEntries[i];
Animate(pDeltaTime, _entry.skeleton, _entry.pose, sIdentityMatrix);
pSkeletalAnimationShader->SetBoneTransforms(_entry.boneCount, _entry.pose);
mMeshes[i]->Render();
}
}
void SkeletalAnimation::RenderStill(SkeletalAnimationShader* pSkeletalAnimationShader) {
for (size_t i = 0; i < mMeshes.size(); i++) {
unsigned int _materialIndex = mMeshToTexture[i];
if (_materialIndex < mTextures.size() && mTextures[_materialIndex]) {
mTextures[_materialIndex]->Enable();
}
MeshEntry& _entry = mMeshEntries[i];
pSkeletalAnimationShader->SetBoneTransforms(_entry.boneCount, _entry.pose);
mMeshes[i]->Render();
}
}
void SkeletalAnimation::ClearModel() {
for (size_t i = 0; i < mMeshes.size(); i++) {
if (mMeshes[i]) {
delete mMeshes[i];
mMeshes[i] = nullptr;
}
}
for (size_t i = 0; i < mTextures.size(); i++) {
if (mTextures[i]) {
delete mTextures[i];
mTextures[i] = nullptr;
}
}
}
void SkeletalAnimation::GetSegment(Segment* pSegment,const std::vector<float>& pTimestamps, const float pDeltaTime) {
unsigned int _segment = 1;
while (pDeltaTime > pTimestamps[_segment]) {
_segment++;
}
float _start = pTimestamps[_segment - 1];
float _end = pTimestamps[_segment];
float _fracture = (pDeltaTime - _start) / (_end - _start);
pSegment->segment = _segment;
pSegment->fracture = _fracture;
}
glm::mat4 SkeletalAnimation::aiToGlmMat4(const aiMatrix4x4& pAiMat) {
glm::mat4 _glmMat;
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
_glmMat[x][y] = pAiMat[y][x];
}
}
return _glmMat;
}
glm::vec3 SkeletalAnimation::aiToGlmVec3(const aiVector3D& pAiVec) {
return glm::vec3(pAiVec.x, pAiVec.y, pAiVec.z); //Swapped Y and Z to correct Blender ups.
}
glm::quat SkeletalAnimation::aiToGlmQuat(const aiQuaternion& pAiQuat) {
return glm::quat(pAiQuat.w, pAiQuat.x, pAiQuat.y, pAiQuat.z);
}
I read my code line by line multiple times to see what I'm doing wrong but I can't think of anything. I don't think my shader is the issue but here's the vertex shader:
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 uv;
layout (location = 2) in vec3 normal;
layout (location = 3) in ivec4 boneIds;
layout (location = 4) in vec4 boneWeights;
out vec2 textureUV;
out vec3 lightNormal;
out vec4 worldPosition;
uniform mat4 model;
uniform mat4 projectionView;
uniform mat4 boneTransforms[50];
void main()
{
mat4 boneTransform = mat4(0.0f);
for(int i = 0; i < 4; i++){
boneTransform += boneTransforms[boneIds[i]] * boneWeights[i];
}
worldPosition = boneTransform * vec4(position, 1.0f);
worldPosition = model * worldPosition;
gl_Position = projectionView * worldPosition;
textureUV = uv;
lightNormal = mat3(transpose(inverse(model * boneTransform))) * normal;
}
The result:
I figured it out. BoneTransforms needed to be moved within the for loop. The same instance was getting over-written each loop cycle.
Related
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;
}
I was creating a custom operating system and I have a problem. I have an array of child components in an array of all opened windows. When I call a function CDraw (Component Draw) on the child array the system crashes with the message "General Protection Fault Detected".
Window array and code:
int openedWindows = 0;
Window* windows[128];
int OpenWindow(Window win) {
windows[0][openedWindows] = win;
openedWindows++;
return openedWindows-1;
};
void CloseWindow(int index) {
for(int i = index+1; i < 127; i++) {
if(i != 127)
windows[0][i] = windows[0][i-1];
else
windows[0][i] = Window();
}
openedWindows--;
};
void CloseAllWindows() {
for(int i = 0; i < 127; i++) {
windows[0][i] = Window();
}
openedWindows = 0;
};
/*Draw Windows*/
for(int i = 0; i < openedWindows; i++)
{
windows[0][i].Update();
}
Where I call the code:
Window wnd = Window("Window");
wnd.Update();
Button btn = Button(wnd, "Hello");
btn.CPosition = Point(10, 10);
btn.BackColor = Color(MediumTurquoise);
btn.parent = &wnd;
btn.parent->AddComponent(btn);
btn.Update();
Button btn2 = Button(wnd, "H2");
btn2.CPosition = Point(100, 100);
btn2.BackColor = Color(Red);
btn2.parent = &wnd;
btn2.parent->AddComponent(btn2);
btn2.Update();
OpenWindow(wnd);
Componet code:
int childIndex = 0;
BaseGuiComponent* children[128];
int BaseGuiComponent::AddComponent(BaseGuiComponent baseGuiComponent) {
children[0][childIndex] = baseGuiComponent;
childIndex++;
return childIndex-1;
};
void BaseGuiComponent::RemoveComponent(int index) {
for(int i = index+1; i < 127; i++) {
if(i != 127)
children[0][i] = children[0][i-1];
else
children[0][i] = BaseGuiComponent();
}
childIndex--;
};
void BaseGuiComponent::ClearComponents() {
for(int i = 0; i < 127; i++) {
children[0][i] = BaseGuiComponent();
}
childIndex = 0;
};
//List components and Update();
void BaseGuiComponent::DrawChildren() {
for(int i = 0; i < childIndex; i++) {
children[0][i].Update();
}
};
Drawing code:
void BaseGuiComponent::CDraw() {
if (strcmp(type,"Window",128)) {
Draw->DrawWindow(BackColor.GetHexColor(), CPosition.X, CPosition.Y, CSize.Width, CSize.Height, 2, CText, WindowStyle, Draw->GetScreenBounds());
DrawChildren();
} else if (strcmp(type,"Button",128)) {
Draw->FillRect(BackColor.GetHexColor(), CGlobalPosition.X*4, CGlobalPosition.Y, CSize.Width*4, CSize.Height, parent->bound/* Conflicting code */);
Draw->PRINTAT(ForeColor.GetHexColor(),CText, CGlobalPosition.X + nabs(CSize.Width - svlen(CText))/2,CGlobalPosition.Y + nabs(CSize.Height-16)/2, bound);
}
};
All help is welcomed. Thanks.
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();
}
}
#include "Field.h"
Field::Field(const std::string& l_title, int size) : m_windows(l_title, sf::Vector2u(size, size)),
m_squareDim(size / 8), m_chessGrid(m_squareDim), m_wTeam(TeamColor::WHITE, m_chessGrid),
m_bTeam(TeamColor::BLACK, m_chessGrid), m_knight(PieceType::W_KNIGHT, sf::Vector2f(105,105))
{
reset();
}
void Field::reset()
{
drawTeamStart();
}
void Field::render()
{
m_windows.BeginDraw();
constructChessBoard();
m_windows.Draw(m_knight.getPieceSprite());
drawTeamStart();
m_windows.EndDraw();
}
void Field::drawTeamStart() //draws both the black and white team in their starting positions
{
for (int i = 0; i < 16; i++) {
m_windows.Draw(m_wTeam.m_chessPieces[i].getPieceSprite());
m_windows.Draw(m_bTeam.m_chessPieces[i].getPieceSprite());
}
}
struct Grid {
sf::Vector2f m_gridMap[8][8];
Grid(float squareDim) {
sf::Vector2f coord;
coord.x += squareDim/2;
coord.y += squareDim/2;
for (int i = 0; i < 8; i++) {
coord.y += squareDim;
for (int j = 0; j < 8; j++) {
coord.x += squareDim;
m_gridMap[i][j] = coord;
}
}
}
};
#pragma once
#include "SFML\Graphics.hpp"
#include "Grid.h"
enum PieceType {
W_BISHOP,
W_PAWN,
W_KING,
W_QUEEN,
W_ROOK,
W_KNIGHT,
B_BISHOP,
B_PAWN,
B_KING,
B_QUEEN,
B_ROOK,
B_KNIGHT
};
class GamePieces
{
public:
GamePieces(){}
GamePieces(const PieceType& type, const sf::Vector2f& position) : m_type(type),m_position(position)
{
switch (type) {
case W_BISHOP:
m_gamePiece.loadFromFile("w_bishop.png");
break;
//other cases are practically the same
}
m_size = m_gamePiece.getSize();
m_gamePieceSprite.setTexture(m_gamePiece);
m_gamePieceSprite.setOrigin(sf::Vector2f(m_size.x/2, m_size.y/2));
m_gamePieceSprite.setPosition(position);
}
sf::Sprite getPieceSprite() const {
return m_gamePieceSprite;
}
private:
sf::Texture m_gamePiece;
sf::Sprite m_gamePieceSprite;
sf::Vector2f m_position;
PieceType m_type;
sf::Vector2u m_size;
};
#pragma once
#include "SFML\Graphics.hpp"
#include "GamePieces.h"
enum TeamColor {
BLACK,
WHITE
};
struct Team {
//16 pieces in regular chess
//map that assigns specific game pieces coordinates
GamePieces m_chessPieces[16];
TeamColor color;
Team(const TeamColor& color, const Grid& grid) { //reference to constant grid variable
sf::Vector2f coord;
switch (color) {
case WHITE:
{
m_chessPieces[0] = GamePieces(PieceType::W_ROOK, grid.m_gridMap[0][0]);
m_chessPieces[1] = GamePieces(PieceType::W_KNIGHT, grid.m_gridMap[0][1]);
m_chessPieces[2] = GamePieces(PieceType::W_BISHOP, grid.m_gridMap[0][2]);
m_chessPieces[3] = GamePieces(PieceType::W_KING, grid.m_gridMap[0][3]);
m_chessPieces[4] = GamePieces(PieceType::W_QUEEN, grid.m_gridMap[0][4]);
m_chessPieces[5] = GamePieces(PieceType::W_BISHOP, grid.m_gridMap[0][5]);
m_chessPieces[6] = GamePieces(PieceType::W_KNIGHT, grid.m_gridMap[0][6]);
m_chessPieces[7] = GamePieces(PieceType::W_ROOK, grid.m_gridMap[0][7]);
int counter = 8;
for (int j = 0; j < 8; j++) {
//arranging pawns left to right on
m_chessPieces[counter] = GamePieces(PieceType::W_PAWN, grid.m_gridMap[1][j]);
counter++;
}
}
break;
default:
{
for (int j = 0; j < 8; j++) {
//arranging pawns left to right on
m_chessPieces[j] = GamePieces(PieceType::B_PAWN, grid.m_gridMap[7][j]);
}
m_chessPieces[8] = GamePieces(PieceType::B_ROOK, grid.m_gridMap[8][0]);
m_chessPieces[9] = GamePieces(PieceType::B_KNIGHT, grid.m_gridMap[8][1]);
m_chessPieces[10] = GamePieces(PieceType::B_BISHOP, grid.m_gridMap[8][2]);
m_chessPieces[11] = GamePieces(PieceType::B_KING, grid.m_gridMap[8][3]);
m_chessPieces[12] = GamePieces(PieceType::B_QUEEN, grid.m_gridMap[8][4]);
m_chessPieces[13] = GamePieces(PieceType::B_BISHOP, grid.m_gridMap[8][5]);
m_chessPieces[14] = GamePieces(PieceType::B_KNIGHT, grid.m_gridMap[8][6]);
m_chessPieces[15] = GamePieces(PieceType::B_ROOK, grid.m_gridMap[8][7]);
}
}
}
};
So the problem is that its not rendering properly, sometimes a few white squares appear in place of the sprite. I've put a GamePiece object directly as a member of the Field class the m_knight as a test, and that renders fine so its nothing wrong with my objects.
I've been working on my spaceInvaders clone and I'm now trying to finish of the project with cleaning the memory leaks.
Currently I'm trying to delete an array of 11 aliensobjects created in a constructor, however whilst doing so the program breaks (crashes) at the destructor of AlienRow.
I've tried the following things:
Created nullpointers in constructor and deleted with this:
for (int i = 0; i < 11; i++)
{
if (alienRow[i] != nullptr)
{
delete alienRow[i];
}
delete *alienRow;
as well as:
delete [] alienRow;
Any pointers to why this issue occurs?
#include "AlienRow.h"
AlienRow::AlienRow(float x, float y, int type){
for (int i = 0; i < 11; i++)
{
alienRow[i] = nullptr;
}
if (type == 1){
for (int i = 0; i < 11; i++)
{
alienRow[i] = new Alien(x, y, "Alien1.png");
x = x + 70;
}
}
if (type == 2){
for (int i = 0; i < 11; i++)
{
alienRow[i] = new Alien(x, y, "Alien2.png");
x = x + 70;
}
}
if (type == 3){
for (int i = 0; i < 11; i++)
{
alienRow[i] = new Alien(x, y, "Alien3.png");
x = x + 70;
}
}
}
AlienRow::~AlienRow(){
/*for (int i = 0; i < 11; i++)
{
if (alienRow[i] != nullptr)
{
delete alienRow[i];
}
delete *alienRow;
}*/
delete [] alienRow;
}
void AlienRow::draw(RenderTarget& target, RenderStates states)const{
for (int i = 0; i < 11; i++)
{
target.draw(*alienRow[i]);
}
}
Alien* AlienRow::getAlienRowA(int nr)const{
return alienRow[nr];
}
bool AlienRow::getAlienMove(float x, float y){
for (int i = 0; i < 11; i++)
{
if (alienRow[i]->moveAlien(x, y) == true)
return true;
}
return false;
}
#pragma once
#include "Alien.h"
#include <iostream>
class AlienRow :public sf::Drawable {
private:
Alien* alienRow[11];
float alienVelocity;
public:
Alien* getAlienRowA(int nr)const;
virtual void draw(RenderTarget& target, RenderStates states)const;
bool getAlienMove(float x, float y);
AlienRow(float x, float y, int type);
~AlienRow();
};
Alien:
#include "Alien.h"
#include <iostream>
Alien::Alien(float x, float y, std::string alien){
alienTexture.loadFromFile(alien);
alienSprite.setTexture(alienTexture);
alienSprite.setPosition(x, y);
alienSprite.setScale(sf::Vector2f(0.7f, 0.7f));
}
Alien::~Alien(){
}
void Alien::draw(RenderTarget& target, RenderStates states)const{
target.draw(alienSprite);
}
void Alien::update(float dt){
}
Sprite Alien::getAlienSprite()const{
return alienSprite;
}
void Alien::moveDeadSprite(){
alienSprite.setPosition(alienSprite.getPosition().x, alienSprite.getPosition().y - 700);
}
bool Alien::moveAlien(float x, float y){
alienSprite.move(x, y);
if (alienSprite.getPosition().y > 540){
return true;
}
return false;
}
#pragma once
#include "Entity.h"
class Alien:public Entity{
private:
Sprite alienSprite;
Texture alienTexture;
float velocity;
public:
Sprite getAlienSprite()const;
void moveDeadSprite();
bool moveAlien(float x, float y);
virtual void draw(RenderTarget& target, RenderStates states)const;
virtual void update(float dt);
Alien(float x, float y, std::string alien);
virtual ~Alien();
};
AlienSwarm
#include "AlienSwarm.h"
AlienSwarm::AlienSwarm(float y){
aRow[0] = new AlienRow(0,y,3);
y = y + 50;
aRow[1] = new AlienRow(0,y,2);
y = y + 50;
aRow[2] = new AlienRow(0, y,3);
y = y + 50;
aRow[3] = new AlienRow(0, y,2);
y = y + 50;
aRow[4] = new AlienRow(0, y,1);
y = y + 50;
}
AlienSwarm::~AlienSwarm(){
for (int i = 0; i < 5; i++)
{
delete aRow[i];
}
}
void AlienSwarm::draw(RenderTarget& target, RenderStates states)const{
for (int i = 0; i < 5; i++){
target.draw(*aRow[i]);
}
}
AlienRow* AlienSwarm::getAlienSwarmA(int nr)const{
return aRow[nr];
}
void AlienSwarm::update(){
}
bool AlienSwarm::getAlienMoveRow(){
for (int i = 0; i < 5; i++)
{
if (aRow[i]->getAlienMove(0, 0.5f) == true)
return true;
}
return false;
}
#pragma once
#include "AlienRow.h"
class AlienSwarm:public Drawable{
private:
AlienRow* aRow[5];
float y;
public:
AlienRow* getAlienSwarmA(int nr)const;
bool getAlienMoveRow();
virtual void draw(RenderTarget& target, RenderStates states)const;
virtual void update();
AlienSwarm(float y);
virtual ~AlienSwarm();
};
Match your new calls to your delete calls.
delete *alienRow;
There is no matching new for this. You effectively delete the first element of your array 12 times. Remove this line.
delete [] alienRow;
You array is not created using new. Remove this line as well.
Use smart pointers and (unique_ptr or shared_ptr) and you do not have to delete them.