I decided to make a multiplayer game in sfml, the map is a text variable
one step lower,! - block with a collider, # - ground.
It looks something like this:
"## !;
! # !;
###;"
I have a special class "Qardrat" that represents a block with a texture, that is, an alternative to a sprite.
class Quardrat {
public:
void spriteSetPosition(int Vx, int Vy) {
sprite.setPosition(Vx, Vy);
}
void LoadTexture(String textureName) {
texture.loadFromFile(textureName);
// RectangleShape tmpSprite(texture);
sprite.setScale(sizeX, sizeY);
sprite.setTexture(&texture);
}
void ShapeMove(int Vx, int Vy) {
sprite.move(Vx, Vy);
//sprite.setPosition(sprite.getPosition().x+Vx, sprite.getPosition().y+Vy);
std::cout << "Сдвинулся на " << Vx << "По x" << std::endl;
}
Quardrat(float x = 0, float y = 0, float sx = 1, float sy = 1, String textureName = "player.png") {
LoadTexture(textureName);
sizeX = sx;
sizeY = sy;
sprite.setPosition(x, y);
sprite.setSize(Vector2f(sx, sy));
}
sf::RectangleShape GetShape() {
return sprite;
}
void DrawShape() {
::window.draw(sprite);
}
float GetSizeX() {
return sizeX;
}float GetSizeY() {
return sizeY;
}
private:
Texture texture;
std::string texutreName = "player.png";
float sizeX = 10;
float sizeY = 10;
//Sprite sprite;
RectangleShape sprite;
};
It is declared as follows: x position, y position, height, width, texture name.
To draw objects, 3 cities are used, which are placed in the square classes:
sloi0, sloi1, player /
here is the drawing code
void DrawOnDisplay(const std::vector<std::reference_wrapper<Quardrat>>& a) {//РИСОВАНИЕ
for (Quardrat i : sloi0)
i.DrawShape();
//::window.draw(i.GetShape());
for (Quardrat i : sloi1)
i.DrawShape();
// ::window.draw(i.GetShape());
for (Quardrat i : a) {
i.DrawShape();
// ::window.draw(i.GetShape());
}
}
And I'll leave the card reading code here, just in case:
for (char block : map) {
if (block == '#') {
Quardrat bl = Quardrat(BlockPosX * StandartBlockSize, BlockPosY * StandartBlockSize, StandartBlockSize, StandartBlockSize);
sloi0.push_back(bl); BlockPosX++;
// }
if (block == '!') {
Quardrat bl = Quardrat(BlockPosX * StandartBlockSize, BlockPosY * StandartBlockSize,
StandartBlockSize / 10, StandartBlockSize / 10, "block.png");
sloi0.push_back(bl); BlockPosX++;
collisions.push_back(bl);
}
if (block == ';') {
BlockPosY++;
BlockPosX = 0;
}
}
And here's the problem - from all the blocks of the map, a texture appears only for one, for all the rest - a white square.
Related
I have a class that has x, y, and mass (which acts as radius) attributes. All of which are floats. I also have this method:
float shrink(float attackerMass) {
float shrinkAmount = attackerMass * GetFrameTime();
mass -= shrinkAmount;
return shrinkAmount;
}
This method is called when another circle is touching the circle, and it shrinks the circle by the right amount (I put an std::cout line underneath mass -= shrinkAmount to test it) but the value of mass is never actually applied to the object. My guess is that I'm somehow changing the value of a copy of my circle object and not the actual referenced one but I have no idea how that'd be happening.
Here's the entire object class if needed (I am using functions from Raylib):
class Blib {
private:
Color color;
Blib* address{ this };
public:
float x;
float y;
float mass;
/* Constructor */
Blib(float x, float y, float mass = 32.0f, Color color = Color{ 255, 255, 255, 200 }) {
this->x = x;
this->y = y;
this->mass = mass;
this->color = color;
}
/* Methods */
void check_collisions(std::vector<Blib> blibs) { //
for (Blib blib : blibs) {
if (CheckCollisionCircles(Vector2{ x, y }, mass, Vector2{ blib.x, blib.y }, blib.mass)) {
if (mass > blib.mass && address != blib.address) {
grow(blib.shrink(mass));
}
}
}
}
void draw() {
DrawCircle(x, y, mass, color);
}
void grow(float amount) {
mass += amount;
}
void move_with_keyboard() {
float speed = 5.0f * mass * GetFrameTime();
if (IsKeyDown(KEY_W)) {
y -= speed;
}
if (IsKeyDown(KEY_A)) {
x -= speed;
}
if (IsKeyDown(KEY_S)) {
y += speed;
}
if (IsKeyDown(KEY_D)) {
x += speed;
}
}
float shrink(float attackerMass) {
float shrinkAmount = attackerMass * GetFrameTime();
mass -= shrinkAmount;
return shrinkAmount;
}
};
Here:
for (Blib blib : blibs)
Simply change to:
for (Blib &blib : blibs)
You want a reference, otherwise you are just changing a temporary variable that disappears at the end of each for loop iteration.
PS: I usually prefer:
for (auto &blib : blibs)
PPS: Your function signature also needs to be a reference:
void check_collisions(std::vector<Blib> &blibs)
I have some code that when compiled, runs an Asteroid Game. I want to make some changes. In place of sprites for the ship, I would like to use trianges. For a bullet, I'd like to use a small rectangle, and finally, a polygon for the asteroids. The code uses an Entity Master Class with a list. Can somebody please elaborate on how to make these changes?
#include <SFML/Graphics.hpp>
#include <time.h>
#include <list>
using namespace sf;
const int W = 1200;
const int H = 800;
float DEGTORAD = 0.017453f;
class Animation
{
public:
float Frame, speed;
Sprite sprite;
std::vector<IntRect> frames;
Animation(){}
Animation (Texture &t, int x, int y, int w, int h, int count, float Speed)
{
Frame = 0;
speed = Speed;
for (int i=0;i<count;i++)
frames.push_back( IntRect(x+i*w, y, w, h) );
sprite.setTexture(t);
sprite.setOrigin(w/2,h/2);
sprite.setTextureRect(frames[0]);
}
void update()
{
Frame += speed;
int n = frames.size();
if (Frame >= n) Frame -= n;
if (n>0) sprite.setTextureRect( frames[int(Frame)] );
}
bool isEnd()
{
return Frame+speed>=frames.size();
}
};
class Entity
{
public:
float x,y,dx,dy,R,angle;
bool life;
std::string name;
Animation anim;
Entity()
{
life=1;
}
void settings(Animation &a,int X,int Y,float Angle=0,int radius=1)
{
anim = a;
x=X; y=Y;
angle = Angle;
R = radius;
}
virtual void update(){};
void draw(RenderWindow &app)
{
anim.sprite.setPosition(x,y);
anim.sprite.setRotation(angle+90);
app.draw(anim.sprite);
CircleShape circle(R);
circle.setFillColor(Color(255,0,0,170));
circle.setPosition(x,y);
circle.setOrigin(R,R);
//app.draw(circle);
}
virtual ~Entity(){};
};
class asteroid: public Entity
{
public:
asteroid()
{
dx=rand()%8-4;
dy=rand()%8-4;
name="asteroid";
}
void update()
{
x+=dx;
y+=dy;
if (x>W) x=0; if (x<0) x=W;
if (y>H) y=0; if (y<0) y=H;
}
};
class bullet: public Entity
{
public:
bullet()
{
name="bullet";
}
void update()
{
dx=cos(angle*DEGTORAD)*6;
dy=sin(angle*DEGTORAD)*6;
// angle+=rand()%7-3; /*try this*/
x+=dx;
y+=dy;
if (x>W || x<0 || y>H || y<0) life=0;
}
};
class player: public Entity
{
public:
bool thrust;
player()
{
name="player";
}
void update()
{
if (thrust)
{ dx+=cos(angle*DEGTORAD)*0.2;
dy+=sin(angle*DEGTORAD)*0.2; }
else
{ dx*=0.99;
dy*=0.99; }
int maxSpeed=15;
float speed = sqrt(dx*dx+dy*dy);
if (speed>maxSpeed)
{ dx *= maxSpeed/speed;
dy *= maxSpeed/speed; }
x+=dx;
y+=dy;
if (x>W) x=0; if (x<0) x=W;
if (y>H) y=0; if (y<0) y=H;
}
};
bool isCollide(Entity *a,Entity *b)
{
return (b->x - a->x)*(b->x - a->x)+
(b->y - a->y)*(b->y - a->y)<
(a->R + b->R)*(a->R + b->R);
}
int main()
{
srand(time(0));
RenderWindow app(VideoMode(W, H), "Asteroids!");
app.setFramerateLimit(60);
Texture t1,t2,t3,t4,t5,t6,t7;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
t3.loadFromFile("images/explosions/type_C.png");
t4.loadFromFile("images/rock.png");
t5.loadFromFile("images/fire_blue.png");
t6.loadFromFile("images/rock_small.png");
t7.loadFromFile("images/explosions/type_B.png");
t1.setSmooth(true);
t2.setSmooth(true);
Sprite background(t2);
Animation sExplosion(t3, 0,0,256,256, 48, 0.5);
Animation sRock(t4, 0,0,64,64, 16, 0.2);
Animation sRock_small(t6, 0,0,64,64, 16, 0.2);
Animation sBullet(t5, 0,0,32,64, 16, 0.8);
Animation sPlayer(t1, 40,0,40,40, 1, 0);
Animation sPlayer_go(t1, 40,40,40,40, 1, 0);
Animation sExplosion_ship(t7, 0,0,192,192, 64, 0.5);
std::list<Entity*> entities;
for(int i=0;i<15;i++)
{
asteroid *a = new asteroid();
a->settings(sRock, rand()%W, rand()%H, rand()%360, 25);
entities.push_back(a);
}
player *p = new player();
p->settings(sPlayer,200,200,0,20);
entities.push_back(p);
/////main loop/////
while (app.isOpen())
{
Event event;
while (app.pollEvent(event))
{
if (event.type == Event::Closed)
app.close();
if (event.type == Event::KeyPressed)
if (event.key.code == Keyboard::Space)
{
bullet *b = new bullet();
b->settings(sBullet,p->x,p->y,p->angle,10);
entities.push_back(b);
}
}
if (Keyboard::isKeyPressed(Keyboard::Right)) p->angle+=3;
if (Keyboard::isKeyPressed(Keyboard::Left)) p->angle-=3;
if (Keyboard::isKeyPressed(Keyboard::Up)) p->thrust=true;
else p->thrust=false;
for(auto a:entities)
for(auto b:entities)
{
if (a->name=="asteroid" && b->name=="bullet")
if ( isCollide(a,b) )
{
a->life=false;
b->life=false;
Entity *e = new Entity();
e->settings(sExplosion,a->x,a->y);
e->name="explosion";
entities.push_back(e);
for(int i=0;i<2;i++)
{
if (a->R==15) continue;
Entity *e = new asteroid();
e->settings(sRock_small,a->x,a->y,rand()%360,15);
entities.push_back(e);
}
}
if (a->name=="player" && b->name=="asteroid")
if ( isCollide(a,b) )
{
b->life=false;
Entity *e = new Entity();
e->settings(sExplosion_ship,a->x,a->y);
e->name="explosion";
entities.push_back(e);
p->settings(sPlayer,W/2,H/2,0,20);
p->dx=0; p->dy=0;
}
}
if (p->thrust) p->anim = sPlayer_go;
else p->anim = sPlayer;
for(auto e:entities)
if (e->name=="explosion")
if (e->anim.isEnd()) e->life=0;
if (rand()%150==0)
{
asteroid *a = new asteroid();
a->settings(sRock, 0,rand()%H, rand()%360, 25);
entities.push_back(a);
}
for(auto i=entities.begin();i!=entities.end();)
{
Entity *e = *i;
e->update();
e->anim.update();
if (e->life==false) {i=entities.erase(i); delete e;}
else i++;
}
//////draw//////
app.draw(background);
for(auto i:entities) i->draw(app);
app.display();
}
return 0;
}
it is not really relevant question to be asked here,
but take a look at this part of code:
Texture t1,t2,t3,t4,t5,t6,t7;
t1.loadFromFile("images/spaceship.png");
t2.loadFromFile("images/background.jpg");
t3.loadFromFile("images/explosions/type_C.png");
t4.loadFromFile("images/rock.png");
t5.loadFromFile("images/fire_blue.png");
t6.loadFromFile("images/rock_small.png");
t7.loadFromFile("images/explosions/type_B.png");
I'm trying to implement collision detection in sfml using the separating axis theorem but my function to get the min translation vector (getMtv()) is always returning that there is a collision (MTV::IsValid()). I was following a tutorial here
but I can't see where I went wrong.
#include <iostream>
#include <math.h>
#include <SFML/Graphics.hpp>
#include <gtest/gtest.h>
typedef sf::Vector2f Vector2;
typedef sf::Vector2f Axis;
typedef sf::Vector2f Projection;
typedef std::vector<Axis> AxesVec;
class MTV
{
private:
bool _valid;
Axis _axis;
float _overlap;
public:
MTV(Axis axis, float overlap, bool valid)
{
_valid = valid;
_overlap = overlap;
_axis = axis;
}
bool IsValid() const
{
return _valid;
}
};
Vector2 perpendicular(Vector2 v)
{
return Vector2(v.y, -v.x);
}
float dot(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.x) + (vec1.y * vec2.y);
}
float magnitude(Vector2 v)
{
return std::sqrt(dot(v,v));
}
class Polygon : public sf::ConvexShape
{
public:
const AxesVec& GetAxes() const
{
return axes;
}
AxesVec axes;
void generateAxes()
{
for (int i = 0; i < getPointCount(); i++)
{
// get the current vertex
Vector2 p1 = getPoint(i); //shape.vertices[i];
// get the next vertex
Vector2 p2 = getPoint(i + 1 == getPointCount() ? 0 : i + 1);
// subtract the two to get the edge vector
Vector2 edge = p1 - p2;
// get either perpendicular vector
Vector2 normal = perpendicular(edge);
// the perp method is just (x, y) => (-y, x) or (y, -x)
axes.push_back(normal / magnitude(normal));
}
};
float cross(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.y) - (vec1.y * vec2.x);
}
Vector2 project(Polygon p, Axis axis)
{
float min = dot(axis, p.getPoint(0)); //axis.dot(shape.vertices[0]);
float max = min;
for (int i = 1; i < p.getPointCount(); i++)
{
// NOTE: the axis must be normalized to get accurate projections
float prj = dot(axis, p.getPoint(i));//axis.dot(shape.vertices[i]);
if (prj < min)
{
min = prj;
}
else if (prj > max)
{
max = prj;
}
}
//Projection proj = new Projection(min, max);
return Projection(min, max);
}
class Collison
{
private:
Vector2 mtv;
Polygon a;
Polygon b;
};
bool overlap(Projection a, Projection b)
{
// x = min & y = max
return !(a.x > b.y || a.x > b.y);
}
float getOverlap(Projection a, Projection b)
{
// x = min & y = max
return (a.y < b.y) ? a.y - b.x : b.y - a.x;
}
MTV getMtv(Polygon a, Polygon b)
{
float overlapMax = std::numeric_limits<float>::infinity();// really large value;
float Overlap;
Axis smallest;// = null;
AxesVec axesA = a.GetAxes();
AxesVec axesB = b.GetAxes();
// loop over the axes1
for (auto&& axis : axesA) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
float o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
for (auto&& axis : axesB) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
double o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
//MTV mtv = new MTV(smallest, overlap);
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return MTV(smallest, Overlap, true);
}
int main(int argc, char **argv)
{
Polygon polygon;
polygon.setPointCount(3);
polygon.setPoint(0, sf::Vector2f(500, 100));
polygon.setPoint(1, sf::Vector2f(250, 500));
polygon.setPoint(2, sf::Vector2f(750, 500));
polygon.setFillColor(sf::Color::Red);
polygon.generateAxes();
Polygon polygon2;
polygon2.setPointCount(3);
polygon2.setPoint(0, sf::Vector2f(100, 0));
polygon2.setPoint(1, sf::Vector2f(50, 150));
polygon2.setPoint(2, sf::Vector2f(150, 150));
polygon2.generateAxes();
//polygon2.setPoint(0, sf::Vector2f(100, 0));
//polygon2.setPoint(1, sf::Vector2f(500, 150));
//polygon2.setPoint(2, sf::Vector2f(250, 150));
polygon2.setFillColor(sf::Color::Green);
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
window.draw(polygon);
window.draw(polygon2);
std::cout << getMtv(polygon, polygon2).IsValid() << std::endl;
// end the current frame
window.display();
}
return 0;
}
I'm trying to create a firework with OpenGL (I must put 100 particles in the position (0,0,0)) with the function
Particle *p[100];
void Build()
{
for (int i = 1; i <= 100; i++)
{
p[i]->pos.x = 0.0;
p[i]->pos.y = 1.0;
p[i]->pos.z = 5.0;
p[i]=AddParticle(*p[i]);
}
}
but I get the following error:
Unhandled exception at 0x771b15de in ass.exe: 0xC0000005: Access violation writing location 0x00000000.
this is the rest of the code:
class Particle
{
public:
Vector3 pos; // current position
Vector3 vel; // velocity
Vector3 restPos; // rest (initial) position
Vector3 oldPos; // previous position
Vector3 acc; // acceleration
Particle()
{
oldPos = restPos = pos = Vector3(0, 0, 0);
Init();
}
Particle(float x, float y, float z)
{
oldPos = restPos = pos = Vector3(x, y, z);
Init();
}
Particle(const Vector3 & _p)
{
oldPos = restPos = pos = _p;
Init();
}
void Init()
{
acc = Vector3(0, 0, 0);
vel = Vector3(0, 0, 0);
}
void Update(const float & time_step)
{
Verlet(time_step);
}
// integration step with Verlet
void Verlet(const float & time_step)
{
Vector3 temp = pos;
pos += vel * time_step + acc * time_step * time_step ;
vel = (temp - oldPos) / time_step;
oldPos = temp;
}
};
# endif // _PARTICLE__
using namespace std;
class ParticleSystem
{
vector<Particle> _particles; // the particles
Vector3 m_vGravity; // gravity force applied to the particles system
float m_fTimeStep; // time step
Vector3 attractor;
public:
ParticleSystem()
{
m_vGravity = Vector3(0, -9.81f, 0);
m_fTimeStep = TIME_STEP;
attractor = Vector3(0, 0, 0);
}
void Reset()
{
_particles.clear();
}
// accessing the fields
void SetGravity(Vector3 g) { m_vGravity = g;}
void SetTimeStep(float ts) { m_fTimeStep = ts;}
// adding a particle
Particle* AddParticle(Particle _p)
{
_particles.push_back(_p);
return &(_particles.back());
}
void Build()
{
for (int i = 1; i <= 100; i++)
{
Particle p;
p.pos.x = 0.0;
p.pos.y = 1.0;
p.pos.z = 5.0;
p[i]=AddParticle(p);
}
}
void Draw()
{
// draw round points
glPointSize(4.f);
glEnable(GL_POINT_SMOOTH);
glAlphaFunc(GL_GREATER,0.5f);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
// draws the particles
glBegin(GL_POINTS);
glColor3f(1.f, 0.f, 0.f);
vector<Particle>::iterator pIt;
for(pIt = _particles.begin(); pIt != _particles.end(); pIt++)
{
Vector3& pos = pIt->pos;
glVertex3f(pos.x, pos.y, pos.z);
}
glEnd();
glEnable(GL_LIGHTING);
}
#endif // __PARTICLE_SYSTEM__
You've declared an array of pointers to Particles, but not actually allocated any of them.
(and as someone else points out, arrays are 0 indexed, not 1 - so your loop is out by 1 anyway)
It's not entirely clear how this is supposed to work, as you seem to be filling in a particle structure, which you pass to AddParticle(), which returns a pointer to a particle, which you put back in the array you've already tried to reference.
Looking at your code, you probably just need something like:
void Build()
{
for (int i = 1; i <= 100; i++)
{
AddParticle(Particle(0.f, 1.f, 5.f));
}
}
No array needed as the particle class looks after the particles.
i think it's because the array goes from 0 to 99...not 1 to 100 .
Change the for statement to for (int i = 0; i < 100; i++) and remember the array starts with a 0
Also i think i know what you're trying to do..try this code:
void Build()
{
Particle p[100];
for (int i = 0; i < 100; i++)
{
p[i].pos.x = 0.0;
p[i].pos.y = 1.0;
p[i].pos.z = 5.0;
AddParticle(p[i]);
}
}
What's wrong with this functions definitions? I've created this two functions and the second one calls the first one, so what i want is, depending on the if in the first one, the calling of AlignCamera(); will change what happens in AlignXAXis();
void AlignCamera();
{
double cx = ox+(0.5*(xmax-xmin))*sx;
double cy = oy+(0.5*(ymax-ymin))*sy;
double cz = oz+(0.5*(zmax-zmin))*sz;
int vx=0;
int vy=0;
int vz=0;
int nx=0;
int ny=0;
int nz=0;
int iaxis = current_widget->GetPlaneOrientation();
if (iaxis == 0)
{
vz = -1;
nx = ox + xmax*sx;
cx = ox + 256*sx;
}
else if (iaxis == 1)
{
vz = -1;
ny = oy + ymax*sy;
cy = oy + 512*sy;
}
else
{
vy = 1;
nz = oz +zmax*sz;
cz = oz + 64*sz;
}
int px = cx+nx*2;
int py = cy+ny*2;
int pz = cz+nz*3;
vtkCamera *camera=ren->GetActiveCamera();
camera->SetViewUp(vx, vy, vz);
camera->SetFocalPoint(cx, cy, cz);
camera->SetPosition(px, py, pz);
camera->OrthogonalizeViewUp();
ren->ResetCameraClippingRange();
renWin->Render();
}
// Define the action of AlignXAxis
void AlignXAxis();
{
int slice_number;
int po = planeX->GetPlaneOrientation();
if (po == 3)
{
planeX->SetPlaneOrientationToXAxes();
slice_number = (xmax-xmin)/2;
planeX->SetSliceIndex(slice_number);
}
else
{
slice_number = planeX->GetSliceIndex();
}
current_widget= planeX;
ui->horizontalScrollBar->setValue(slice_number);
ui->horizontalScrollBar->setMinimum(xmin);
ui->horizontalScrollBar->setMaximum(xmax);
AlignCamera();
}
the variables needed are defined before it, such as ox, oy, oz....
When i run it it says undefined reference to `AlignCamera()' or 'AlignXAxis()'.
void AlignCamera(); //This is merely a prototype, not a declaration.
Remove the Semicolon, or create a declaration afterwards.
void AlignCamera(); //Prototype
void AlignCamera() { //Declaration
//Do Stuff
}
The same applies for the other function. Remove that semicolon.
Remove the semicolons, so:
void AlignCamera();
{
...
}
becomes
void AlignCamera()
{
...
}