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();
}
}
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 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.
I have a custom QGraphicsItemGroup, with fixed set of children items. I need to make it resizable(already done), but, while resizing, boundingRect is not updating -- though, all child items are drawn correctly. I've tried adding prepareGeometryChange() and update() in different places of the program, but that hasn't helped.
Even this implementation returns default boundingRect:
QRectF FigureGraphicsItemGroup::boundingRect() const
{
return childrenBoundingRect().adjusted(0, 0, 50, 0);
}
And some necessary code(NB no custom painting):
m_right: right control for resize.
QRectF FigureGraphicsItemGroup::boundingRect() const
{
return childrenBoundingRect();
}
void FigureGraphicsItemGroup::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
QPointF pos = event->pos();
if (m_right->contains(pos) && m_right->isVisible())
{
m_isResized = true;
}
else
QGraphicsItemGroup::mousePressEvent(event);
}
void FigureGraphicsItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF pos = event->pos();
if (m_isResized)
{
if (m_previous.x() == -1 && m_previous.y() == -1)
m_previous = pos;
m_delta = pos.x() - m_previous.x();
m_previous = pos;
QGraphicsItem::prepareGeometryChange();
recalculatePositions();
}
else
{
QGraphicsItemGroup::mouseMoveEvent(event);
}
}
void FigureGraphicsItemGroup::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
QPointF pos = event->pos();
if (m_right->contains(pos) && m_right->isVisible())
{
setCursor(Qt::SizeHorCursor);
}
else
{
setCursor(Qt::ArrowCursor);
QGraphicsItemGroup::hoverMoveEvent(event);
}
}
void FigureGraphicsItemGroup::reset()
{
m_isResized = false;
m_delta = 0;
m_previous = QPointF(-1 , -1);
}
void FigureGraphicsItemGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
reset();
QGraphicsItemGroup::mouseReleaseEvent(event);
}
QVariant FigureGraphicsItemGroup::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change)
{
case ItemSelectedHasChanged:
m_isSelected = isSelected();
m_right->setVisible(m_isSelected);
break;
}
return QGraphicsItem::itemChange(change, value);
}
void FigureGraphicsItemGroup::recalculatePositions()
{
int sumX = 1;
QFontMetrics fm(m_zoneNumberSimpleTextItem->font());
m_routeNumberSimpleTextItem->setPos(sumX, m_middle - fm.height());
sumX += m_routeNumberSimpleTextItem->boundingRect().width() * SPACING;
//-------------------------------------------------------------------------------------------
int diameter = fm.height() * SPACING;
int pixLength = fm.width(m_zoneNumberSimpleTextItem->text());
if (pixLength > diameter)
diameter = pixLength;
QPen pen(Qt::red);
pen.setWidth(1);
m_zoneCircleEllipseItem->setRect(sumX, m_middle - diameter, diameter, diameter);
m_zoneCircleEllipseItem->setPen(pen);
m_zoneNumberSimpleTextItem->setPos(sumX + fm.width(m_zoneNumberSimpleTextItem->text()) / 2,
m_middle - fm.height());
sumX += m_zoneCircleEllipseItem->boundingRect().width() * SPACING;
//-------------------------------------------------------------------------------------------
m_fuelSimpleTextItem->setPos(sumX, m_middle * 1.1);
//-------------------------------------------------------------------------------------------
m_leftCornerSvgItem->setPos(sumX, m_middle - m_leftCornerSvgItem->boundingRect().height() / 4);
sumX += m_leftCornerSvgItem->boundingRect().width() * m_scale;
//-------------------------------------------------------------------------------------------
pen.setColor(m_blue);
pen.setWidth(4);
m_leftLineItem->setPen(pen);
int length = m_leftLineItem->line().length() + m_delta / 2;
length = length < 0 ? 0 : length;
m_leftLineItem->setLine(sumX, m_middle, sumX + length, m_middle);
sumX += m_leftLineItem->boundingRect().width();
//-------------------------------------------------------------------------------------------
m_exerciseSvgItem->setPos(sumX - 2, m_middle - m_exerciseSvgItem->boundingRect().height() / 4);
sumX += m_exerciseSvgItem->boundingRect().width() * m_scale;
//-------------------------------------------------------------------------------------------
pen.setColor(m_blue);
pen.setWidth(4);
m_rightLineItem->setPen(pen);
length = m_rightLineItem->line().length() + m_delta / 2;
length = length < 0 ? 0 : length;
m_rightLineItem->setLine(sumX , m_middle, sumX + length, m_middle);
sumX += m_rightLineItem->boundingRect().width();
//-------------------------------------------------------------------------------------------
m_rightCornerSvgItem->setPos(sumX - 2, m_middle - m_rightCornerSvgItem->boundingRect().height() / 4);
sumX += m_rightCornerSvgItem->boundingRect().width() * m_scale;
//-------------------------------------------------------------------------------------------
m_right->setRect(sumX, m_middle, 4, 4);
//-------------------------------------------------------------------------------------------
}
UPD
A little hack helped me: just add removeFromGroup & addToGroup of some item during resize -- and boundingRect will be drawn correctly. But it looks a little bit strange.
I'm having an error.
"Vector subscript is out of range, line 932."
I have two enemy types, an array of asteroids and then a single enemy on it's own. They are made exactly the same except the asteroids are multiple in number, and the Borg is on it's own. I've tracked the error down to the Borg's update method, which is exactly the same as the Asteroids method with some name changes for the Borg. I've tried changing the "for" to "if" and I have tried to change the vector array to a D3DXVECTOR3. I think it's an array error but my programming knowledge is limited. Here are the update methods:
asteroidgamestate.h
#ifndef ASTEROIDSGAMESTATE
#define ASTEROIDSGAMESTATE
#include "Game Engine.h"
#include "Game Constants.h"
#include <vector>
class AsteroidsGameState:public GameState
{
private:
// STL vector to hold a collection of asteroid game sprites.
std::vector<GameSprite*> m_pAsteroids;
// STL vector to hold motion vectors for each asteroid.
std::vector<D3DXVECTOR3*> m_vAsteroidMotionVectors;
// STL vector to hold scaling factors for each asteroid.
std::vector<D3DXVECTOR2*> m_vAsteroidRotation;
public:
AsteroidsGameState() { }
~AsteroidsGameState()
{
this->Release();
}
//Initialises Asteroids & Borg cube
virtual bool Init()
{
D3DXVECTOR3 cSpritePosition;
GameSprite* asteroid;
D3DXVECTOR3* motionVector;
D3DXVECTOR2* rotation;
// Set up the asteroids.
for (int i = 0; i < MaximumNumberOfAsteroids / 2; i++)
{
asteroid = new GameSprite();
if (!asteroid->Init(420,425,true,L"asteroid.png"))
return false;
// Set the sprites current position.
cSpritePosition.x = (float)(100 + MathsUtilities::Get().GetRandomNumber(0, Graphics2D::Get().GetWindowWidth() - 100));
cSpritePosition.y = 1.0f;
cSpritePosition.z = 0.9f;
asteroid->SetSpritePosition(cSpritePosition);
// Set the sprites motion vector
asteroid->SetTranslationMatrix(D3DXVECTOR3(1.0f, 1.0f, 0.0f));
asteroid->SetAlive();
asteroid->SetVisible();
float scale = ((float)MathsUtilities::Get().GetRandomNumber(100, 1000)/3000.0f);
asteroid->SetScaleMatrix(scale, scale);
asteroid->SetRotationMatrix(0.0f);
this->m_pAsteroids.push_back(asteroid);
motionVector = new D3DXVECTOR3(0.0f, 0.0f, 0.0f);
motionVector->x = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->z = 0.0f;
this->m_vAsteroidMotionVectors.push_back(motionVector);
rotation = new D3DXVECTOR2(0.0f, 0.0f);
rotation->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/10000.0f) + 0.001f;
this->m_vAsteroidRotation.push_back(rotation);
}
for (int i = MaximumNumberOfAsteroids / 2; i < MaximumNumberOfAsteroids; i++)
{
asteroid = new GameSprite();
if (!asteroid->Init(420,425,true,L"asteroid2.png"))
return false;
// Set the sprites current position.
cSpritePosition.x = (float)(100 + MathsUtilities::Get().GetRandomNumber(0, Graphics2D::Get().GetWindowWidth() - 100));
cSpritePosition.y = 1.0f;
cSpritePosition.z = 0.9f;
asteroid->SetSpritePosition(cSpritePosition);
// Set the sprites motion vector
asteroid->SetTranslationMatrix(D3DXVECTOR3(1.0f, 1.0f, 0.0f));
asteroid->SetAlive();
asteroid->SetVisible();
float scale = ((float)MathsUtilities::Get().GetRandomNumber(100, 1000)/3000.0f);
asteroid->SetScaleMatrix(scale, scale);
asteroid->SetRotationMatrix(0.0f);
this->m_pAsteroids.push_back(asteroid);
motionVector = new D3DXVECTOR3(0.0f, 0.0f, 0.0f);
motionVector->x = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->z = 0.0f;
this->m_vAsteroidMotionVectors.push_back(motionVector);
rotation = new D3DXVECTOR2(0.0f, 0.0f);
rotation->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/10000.0f) + 0.001f;
this->m_vAsteroidRotation.push_back(rotation);
}
//Spawns one Borg
for (int i = 2 / 2; i < 2; i++)
{
asteroid = new GameSprite();
int BorgHealth = 4;
if (!asteroid->Init(420,425,true,L"borgcube.png"))
return false;
// Set the sprites current position.
/*if (BorgHealth < 4)
{
D3DXCOLOR(1.0f,1.0f,0.0f, 1.0f);
}*/
cSpritePosition.x = (float)(100 + MathsUtilities::Get().GetRandomNumber(0, Graphics2D::Get().GetWindowWidth() - 100));
cSpritePosition.y = 1.0f;
cSpritePosition.z = 0.9f;
asteroid->SetSpritePosition(cSpritePosition);
// Set the sprites motion vector
asteroid->SetTranslationMatrix(D3DXVECTOR3(1.0f, 1.0f, 0.0f));
asteroid->SetAlive();
asteroid->SetVisible();
float scale = ((float)MathsUtilities::Get().GetRandomNumber(999, 1000)/3000.0f);
asteroid->SetScaleMatrix(scale, scale);
asteroid->SetRotationMatrix(0.0f);
this->m_pAsteroids.push_back(asteroid);
motionVector = new D3DXVECTOR3(0.0f, 0.0f, 0.0f);
motionVector->x = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->z = 0.0f;
this->m_vAsteroidMotionVectors.push_back(motionVector);
rotation = new D3DXVECTOR2(0.0f, 0.0f);
rotation->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/10000.0f) + 0.001f;
this->m_vAsteroidRotation.push_back(rotation);
}
return true;
}
// Update pposition, rotation of asteroids.
virtual void Update()
{
GameSprite* asteroid;
int i = 0;
std::vector<GameSprite*>::iterator it;
for (std::vector<GameSprite*>::iterator it = m_pAsteroids.begin(); it != m_pAsteroids.end(); it++)
{
asteroid = *it;
if (m_vAsteroidRotation[i]->y <= 0)
m_vAsteroidRotation[i]->x -= m_vAsteroidRotation[i]->y;
else
m_vAsteroidRotation[i]->x += m_vAsteroidRotation[i]->y;
asteroid->SetRotationMatrix(m_vAsteroidRotation[i]->x);
i++;
if (i >= MaximumNumberOfAsteroids)
i = 0;
if (asteroid->GetAlive())
{
asteroid->SetTranslationMatrix(*m_vAsteroidMotionVectors[i]);
asteroid->Update();
}
asteroid->CheckBoundary();
}
}
// At this time no action is required on entering the state.
virtual void Enter() { }
// At this time no action is required when leaving the state.
virtual void Exit() { }
// Render asteroids.
virtual void Render()
{
GameSprite* asteroid;
// Render all the asteroids.
std::vector<GameSprite*>::iterator it;
for (std::vector<GameSprite*>::iterator it = m_pAsteroids.begin(); it != m_pAsteroids.end(); it++)
{
asteroid = *it;
asteroid->Render();
}
}
// Free allocated resources.
virtual void Release()
{
// Remove Vector classes containing game objects.
this->FreeSTL(m_pAsteroids);
this->FreeSTL(m_vAsteroidMotionVectors);
this->FreeSTL(m_vAsteroidRotation);
}
// Getter functions.
// Get the STL vector to hold a collection of asteroid game sprites.
std::vector<GameSprite*> GetAsteroids() { return this-> m_pAsteroids; }
// Get the STL vector to hold motion vectors for each asteroid.
std::vector<D3DXVECTOR3*> GetAsteroidMotionVectors() { return this->m_vAsteroidMotionVectors; }
// Get the STL vector to hold scaling factors for each asteroid.
std::vector<D3DXVECTOR2*> GetAsteroidRotation() { return this->m_vAsteroidRotation; }
// Private template function to free allocatted resources.
private:
// Template methods to help destroy game objects.
template<typename T>
void FreeSTL(std::vector<T*> &list)
{
std::vector<T*>::iterator it;
it = list.begin();
while(it != list.end())
{
if ((*it) != NULL)
{
delete (*it);
it = list.erase(it);
}
else
it++;
}
list.clear();
}
// New game level requires bringing the asteroids back to life.
void NextLevelOfAsteroids()
{
GameSprite* asteroid;
D3DXVECTOR3 cSpritePosition;
float scale;
int i = 0;
std::vector<GameSprite*>::iterator it;
for (std::vector<GameSprite*>::iterator it = m_pAsteroids.begin(); it != m_pAsteroids.end(); it++)
{
asteroid = *it;
// Set the sprites current position.
cSpritePosition.x = (float)(100 + MathsUtilities::Get().GetRandomNumber(0, Graphics2D::Get().GetWindowWidth() - 100));
cSpritePosition.y = 1.0f;
cSpritePosition.z = 0.9f;
asteroid->SetSpritePosition(cSpritePosition);
// Set the sprites motion vector.
asteroid->SetTranslationMatrix(D3DXVECTOR3(1.0f, 1.0f, 0.0f));
asteroid->SetAlive();
asteroid->SetVisible();
// Scale the asteroids.
scale = ((float)MathsUtilities::Get().GetRandomNumber(100, 1000)/3000.0f);
asteroid->SetScaleMatrix(scale, scale);
asteroid->SetRotationMatrix(0.0f);
// Set motion vectors for the asteroids.
m_vAsteroidMotionVectors[i]->x = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
m_vAsteroidMotionVectors[i]->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
// Set up rotation vector for the asteroids.
m_vAsteroidRotation[i]->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/10000.0f) + 0.001f;
i++;
}
}
};
#endif
borggamestate.h
#pragma once
#ifndef BORGGAMESTATE
#define BORGGAMESTATE
#include "Game Engine.h"
#include "Game Constants.h"
#include <vector>
class BorgGameState:public GameState
{
private:
// STL vector to hold a collection of borg game sprites.
std::vector<GameSprite*> m_pBorg;
// STL vector to hold motion vectors for the borg.
std::vector<D3DXVECTOR3*> m_vBorgMotionVectors;
// STL vector to hold scaling factors for the borg.
std::vector<D3DXVECTOR2*> m_vBorgRotation;
public:
BorgGameState() { }
~BorgGameState()
{
this->Release();
}
//Initialises Borg cube
virtual bool Init()
{
D3DXVECTOR3 cSpritePosition;
GameSprite* borg;
D3DXVECTOR3* motionVector;
D3DXVECTOR2* rotation;
// Set up the borg.
//Spawns one Borg
for (int i = 2 / 2; i < 2; i++)
{
borg = new GameSprite();
int BorgHealth = 4;
if (!borg->Init(420,425,true,L"borgcube.png"))
return false;
// Set the sprites current position.
/*if (BorgHealth < 4)
{
D3DXCOLOR(1.0f,1.0f,0.0f, 1.0f);
}*/
cSpritePosition.x = (float)(100 + MathsUtilities::Get().GetRandomNumber(0, Graphics2D::Get().GetWindowWidth() - 100));
cSpritePosition.y = 1.0f;
cSpritePosition.z = 0.9f;
borg->SetSpritePosition(cSpritePosition);
// Set the sprites motion vector
borg->SetTranslationMatrix(D3DXVECTOR3(1.0f, 1.0f, 0.0f));
borg->SetAlive();
borg->SetVisible();
float scale = ((float)MathsUtilities::Get().GetRandomNumber(999, 1000)/3000.0f);
borg->SetScaleMatrix(scale, scale);
borg->SetRotationMatrix(0.0f);
this->m_pBorg.push_back(borg);
motionVector = new D3DXVECTOR3(0.0f, 0.0f, 0.0f);
motionVector->x = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
motionVector->z = 0.0f;
this->m_vBorgMotionVectors.push_back(motionVector);
rotation = new D3DXVECTOR2(0.0f, 0.0f);
rotation->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/10000.0f) + 0.001f;
this->m_vBorgRotation.push_back(rotation);
}
return true;
}
// Update position, rotation of borg.
virtual void Update()
{
GameSprite* borg;
int i = 0;
std::vector<GameSprite*>::iterator it;
for (std::vector<GameSprite*>::iterator it = m_pBorg.begin(); it != m_pBorg.end(); it++)
{
borg = *it;
if (m_vBorgRotation[i]->y <= 0)
m_vBorgRotation[i]->x -= m_vBorgRotation[i]->y;
else
m_vBorgRotation[i]->x += m_vBorgRotation[i]->y;
borg->SetRotationMatrix(m_vBorgRotation[i]->x);
i++;
if (i >= MaximumNumberOfAsteroids)
i = 0;
if (borg->GetAlive())
{
borg->SetTranslationMatrix(*m_vBorgMotionVectors[i]);
borg->Update();
}
borg->CheckBoundary();
}
}
// At this time no action is required on entering the state.
virtual void Enter() { }
// At this time no action is required when leaving the state.
virtual void Exit() { }
// Render borg.
virtual void Render()
{
GameSprite* borg;
// Render borg.
std::vector<GameSprite*>::iterator it;
for (std::vector<GameSprite*>::iterator it = m_pBorg.begin(); it != m_pBorg.end(); it++)
{
borg = *it;
borg->Render();
}
}
// Free allocated resources.
virtual void Release()
{
// Remove Vector classes containing game objects.
this->FreeSTL(m_pBorg);
this->FreeSTL(m_vBorgMotionVectors);
this->FreeSTL(m_vBorgRotation);
}
// Getter functions.
// Get the STL vector to hold a collection of borg game sprites.
std::vector<GameSprite*> GetBorg() { return this-> m_pBorg; }
// Get the STL vector to hold motion vectors for each borg.
std::vector<D3DXVECTOR3*> GetBorgMotionVectors() { return this->m_vBorgMotionVectors; }
// Get the STL vector to hold scaling factors for the borg.
std::vector<D3DXVECTOR2*> GetBorgRotation() { return this->m_vBorgRotation; }
// Private template function to free allocatted resources.
private:
// Template methods to help destroy game objects.
template<typename T>
void FreeSTL(std::vector<T*> &list)
{
std::vector<T*>::iterator it;
it = list.begin();
while(it != list.end())
{
if ((*it) != NULL)
{
delete (*it);
it = list.erase(it);
}
else
it++;
}
list.clear();
}
// New game level requires bringing the borg back to life.
void NextLevelOfBorg()
{
GameSprite* borg;
D3DXVECTOR3 cSpritePosition;
float scale;
int i = 0;
std::vector<GameSprite*>::iterator it;
for (std::vector<GameSprite*>::iterator it = m_pBorg.begin(); it != m_pBorg.end(); it++)
{
borg = *it;
// Set the sprites current position.
cSpritePosition.x = (float)(100 + MathsUtilities::Get().GetRandomNumber(0, Graphics2D::Get().GetWindowWidth() - 100));
cSpritePosition.y = 1.0f;
cSpritePosition.z = 0.9f;
borg->SetSpritePosition(cSpritePosition);
// Set the sprites motion vector.
borg->SetTranslationMatrix(D3DXVECTOR3(1.0f, 1.0f, 0.0f));
borg->SetAlive();
borg->SetVisible();
// Scale the borg.
scale = ((float)MathsUtilities::Get().GetRandomNumber(100, 1000)/3000.0f);
borg->SetScaleMatrix(scale, scale);
borg->SetRotationMatrix(0.0f);
// Set motion vectors for the borg.
m_vBorgMotionVectors[i]->x = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
m_vBorgMotionVectors[i]->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/150.0f) + 0.25f;
// Set up rotation vector for the borg.
m_vBorgRotation[i]->y = (float)(MathsUtilities::Get().GetRandomNumber(-1000, 1000)/10000.0f) + 0.001f;
i++;
}
}
};
endif
Thanks for your help, and sorry if I've missed anything.
It is hard to say with the information provided, but
your problem might be the here:
In BorgGameState.h Update()
borg = *it;
if (m_vBorgRotation[i]->y <= 0)
m_vBorgRotation[i]->x -= m_vBorgRotation[i]->y;
else
m_vBorgRotation[i]->x += m_vBorgRotation[i]->y;
borg->SetRotationMatrix(m_vBorgRotation[i]->x);
i++;
if (i >= MaximumNumberOfAsteroids) // <--- should this be MaximumNumberOfBorg instead?
i = 0;
If m_vBorgRotation has fewer elements than MaximumNumberOfAsteroids you will get such an error.
OK, I have a vector (have also tried an array) of pointers to objects class GameObject-
//GameObject* objPriority_vec [oc+1];
std::vector<GameObject*> objPriority_vec(oc+1);
and have successfully filled it with pointers to objects of derived classes of GameObject
(MapObject and PlayerCharacter)
for(int o_r = 1; o_r <= oc; o_r++)
{
std::string render_ref = CurrentArea->ObjectRef[o_r];
MapObject* render_obj = CurrentArea->ObjectMap[render_ref];
objPriority_vec[o_r] = render_obj;
}
objPriority_vec[0] = Player_1; // Player_1 is a pointer to obj
// PlayerCharacter
But, very strangely, I cannot seem to access any of the members of any of the objects pointed to
by any of the pointers in the vector/array, even though I have verified that they are in there. For
sake of debugging I have:
GameObject* prioritycheck = objPriority_vec[0]; //has been explicitly declared
//as Player_1
//When tried one a time
if( prioritycheck == Player_1 ) gameRunning = false; // returns false
//(when it should)
if( Player_1->Pos_y > 500) gameRunning = false; // returns false
if( objPriority_vec[0]->Pos_y > 500) gameRunning = false; // does not
if( prioritycheck->Pos_y > 500) gameRunning = false; // does not
So once the pointer has been stored in the vector, it seems to know what it is,
but not what any of its members are... any ideas? I can't seem to comprehend a universe
where this logic can exist...
Class Definitions:
class GameObject
{
public:
std::string Graphic_path;
int height;
int width;
int Pos_x;
int Pos_y;
int Vel;
m_dir Dir;
bool moving;
bool colliding;
CollisionBox cCollisionBox;
virtual void Move(){}
virtual void Show(SDL_Surface*, SDL_Surface*){}
virtual void Add(){}
GameObject() {Graphic_path = "NULL"; Pos_x = 0; Pos_y = 0; height = 0; width = 0;}
};
class MapObject : public GameObject
{
public:
SDL_Surface* Graphic;
std::string Graphic_path;
int height;
int width;
int Pos_x;
int Pos_y;
int Vel;
m_dir Dir;
bool moving;
bool colliding;
CollisionBox cCollisionBox;
bool SetCollisionBox(int x, int y, int w, int h)
{
cCollisionBox.h = h;
cCollisionBox.w = w;
cCollisionBox.x_off = x;
cCollisionBox.y_off = y;
}
bool CheckCollide(){return false;}
void HandleCollide (int vel_x, int vel_y, int vel, m_dir dir)
{
switch (dir)
{
case Up:
break;
case Down:
break;
case Left:
break;
case Right:
break;
}
}
virtual void Move(int v, m_dir dir)
{
switch (dir)
{
case Up:
Pos_y -= v;
break;
case Down:
Pos_y += v;
break;
case Left:
Pos_x -= v;
break;
case Right:
Pos_x += v;
break;
}
}
void StandStill()
{
Vel = 0;
moving = false;
}
virtual void Show(SDL_Surface*, SDL_Surface*){}
virtual void Add(){}
MapObject()
{
Graphic = NULL; Graphic_path = "NULL";
Pos_x = 0; Pos_y = 0;
height = 0; width = 0;
colliding = false; moving = false;
}
};
class PlayerCharacter : public GameObject
{
public:
int Pos_x;
int Pos_y;
int Vel;
int Vel_x;
int Vel_y;
int frame;
int frame_count;
m_dir Dir;
bool moving;
bool colliding;
SDL_Rect CharClip[20];
CollisionBox cCollisionBox;
void SetClip_Walk()
{
int CharWidth = 22;
int CharHeight = 45;
int CharGap = 6;
for (int z = 0; z <= 19; z++)
{
CharClip[ z ].x = (z * CharWidth) + (z * CharGap);
CharClip[ z ].y = 0;
CharClip[ z ].w = CharWidth;
CharClip[ z ].h = CharHeight;
}
}
PlayerCharacter()
{
Pos_x = 0; Pos_y = 0; Vel_x = 0; Vel_y = 0;
Vel = 0; moving = false; colliding = false;
frame = 0; frame_count = 0;
Dir = Down;
SetClip_Walk();
}
bool SetCollisionBox(int x, int y, int w, int h)
{
cCollisionBox.h = h;
cCollisionBox.w = w;
cCollisionBox.x_off = x;
cCollisionBox.y_off = y;
}
void HandleCollide ()
{
Pos_y -= (Vel_y);
Pos_x -= (Vel_x);
cCollisionBox.x = Pos_x + cCollisionBox.x_off;
cCollisionBox.y = Pos_y + cCollisionBox.y_off;
}
void Move(int v_x, int v_y, int v, m_dir dir)
{
switch (dir)
{
case Up:
Pos_y += v_y;
break;
case Down:
Pos_y += v_y;
break;
case Left:
Pos_x += v_x;
break;
case Right:
Pos_x += v_x;
break;
}
cCollisionBox.x = Pos_x + cCollisionBox.x_off;
cCollisionBox.y = Pos_y + cCollisionBox.y_off;
}
void StandStill()
{
Vel = 0; Vel_x = 0; Vel_y = 0;
moving = false;
colliding = false;
}
void Show(SDL_Surface* source, SDL_Surface* dest)
{
if (Vel != 0) frame_count++;
if (frame_count > 3) {frame++; frame_count = 0;}
if (frame > 4) frame = 1;
if (Vel == 0) {frame = 0; frame_count = 0;}
switch (Dir)
{
case Up:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame]);
break;
case Down:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame+5]);
break;
case Left:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame+10]);
break;
case Right:
ApplySurface (Pos_x, Pos_y, source, OutputScreen, &CharClip[frame+15]);
break;
}
}
};
Thank you, all your help and time is greatly appreciated!
You have a base class GameObject which has instance variables Pos_x, Pos_y, etc. You have then subclassed this with MapObject, PlayerObject which have their own instance variables of the same name. This results in each of the derived classes having two of these variables - (one for the base, site for the derived).
You then access these via a pointer to GameObject* which will only provide access to the base class instance variables. As your tests show these do not contain the values you are expecting.
You do not need to declare these instance variables in both base and subclasses. It does not look like having separate variables is serving any purpose in this case; rather it is stopping your code from working. The defined class should only define additional fields on top of those in the base class.
"If you want to compare arbitrary class hierarchies, the safe bet is to make them polymorphic and use dynamic_cast."
See https://stackoverflow.com/a/5662867/912757
try to change for example this statement
if( prioritycheck == Player_1 ) gameRunning = false;
to
if( dynamic_cast<PlayerCharacter *>( prioritycheck ) == Player_1 ) gameRunning = false;