I want to convert my image which is a .bmp file into a physics body. I have tried but it does not work i.e I do not get the desired result. I have searched alot about it o google and finally asking you all to please help me out as I am new to it. Also I am wondering is there really a way to convert images into a box2D body or We simple cannot do that ? I have tried the following code :
My addBrick Function
b2Body* addBrick(int x,int y,int w,int h,bool dyn=true)
{
b2BodyDef bodydef;
bodydef.position.Set(x*P2M,y*P2M); //Setting body position
if(dyn)
{
bodydef.type=b2_dynamicBody; // dynamic body means body will move
}
b2Body* body=world->CreateBody(&bodydef); //Creating box2D body
b2PolygonShape shape; //Creating shape object
shape.SetAsBox(P2M*w,P2M*h);
////////////// Adding Fixtures(mass, density etc) //////////////
b2FixtureDef fixturedef;
fixturedef.shape=&shape;
fixturedef.density=1.0;
fixturedef.restitution = 0.7;
body->CreateFixture(&fixturedef);
return body;
}
drawbrick logic:
void drawbrick()
{
pix[0].readBMPFile("brick.bmp");
pix[0].mDraw();
}
declaration as b2Body
b2Body* myBrick;
calling functions:
myBrick = addBrick(100,0,10,10);
drawbrick();
Where am I going wrong? Can somebody please spot my mistakes??
The most effective way I have found to convert any sort of image into a Box2D body is by using the PhysicsEditor tool (link). I'm not affiliated with them and I am an independent software developer developer.
The editor allows you to import your image then automatically create polygons that you can import into a "shape cache" and then load into the bodies when you create them.
The Shape Cache API (which you can also get from their site) looks like this:
class Box2DShapeCache
{
public:
// Static interface
static Box2DShapeCache& instance(void);
public:
bool init();
void addShapesWithFile(const std::string &plist);
b2Fixture* addHullFixtureToBody(b2Body *body, const std::string &shape);
/* Shapes created in the physics editor are in pixel dimensions. When they are loaded
* they are normalized to the size of maximum of the width/height.
*
*/
void addFixturesToBody(b2Body *body, const std::string &shape, float32 scaleMeters);
CCPoint anchorPointForShape(const string& shape);
CCSize imageSizeForShape(const string& shape);
const std::vector<b2Vec2>& hullPointsForShape(const std::string &shape);
void reset();
float getPtmRatio() { return ptmRatio; }
~Box2DShapeCache() {}
private:
std::map<std::string, BodyDef *> shapeObjects;
Box2DShapeCache(void) {}
float ptmRatio;
};
NOTE 1 - I have used this with Cocos2d-x very effectively. In the video here (link), it was used to create the asteroids the spiders are walking on.
NOTE 2 - The original class was called GB2ShapeCache. It was written in objective-c and has been ported (here) to C++. If you need another C++ version, let me know (mine is slightly modded to import convex hulls from the tool) and I can help.
Was this helpful?
Related
It's easier for me to explain this kind of stuff in videogame terms. I'll try to be as clear as possible please bear with me...
I have a Bullet class that's made of different components, such as a Sprite component and a Transform Component... It would look something like this:
class Bullet
{
public:
Bullet( texture2D texture, Rectangle sourceRectangle, Rectangle destinationRectangle )
Bullet();
~Bullet();
// Returns a pointer to its sprite component so that I can use it wherever I want in the scene:
Sprite* const Sprite() const{ return this->sprite; }
// Setters:
void SetAngle( float new_angle ){ this->angle = new_angle; }
void SetSpeed( float new_speed ){ this->speed = new_speed; }
void SetRadius( float new_radius ){ this->radius = new_radius; }
private:
// Sprite component:
Sprite* sprite;
private:
// Regular member data:
float angle;
float speed;
float radius;
};
The sprite component is simply another class that holds a texture, source rectangle, destination rectangle, and some member functions to manipulate it (Move, Rotate, SetTexture, etc ). Nothing really special. It gets initialized within the constructor
What I need to do is to be able to copy one pointer to a bullet object entirely to another new pointer to a bullet, including the sprite component. Something like this:
// These arguments will be "fed" into the sprite component
Bullet* bullet1 = new Bullet( texture, sourceRect, destRect );
Bullet* bullet2 = new Bullet(); // Using default constructor.
*bullet2 = *bullet1;
Technically, doing it this way works. However, only the regular member data gets copied I think, but not the sprite component. It only points to the first bullet's sprite component. At least that's what I think is happening.
Hopefully I was clear explaining this issue, Thanks for taking the time.
Transforming a sprite in SFML, does not regard it's new origin.
In my case sf::Sprite is rotating around the axis that is in the left top corner ({0,0}) regardless its origin. Setting new origin with .setOrigin() earlier takes no effect.
I am sure that sprite is getting the right origin position earlier which is center of rectangle.
My code:
In each of my Card class constructors I set the origin of my sprite.
card_sprite.setOrigin(Card::get_default_single_card_size().x*Game::get_scale()/2,Card::get_default_single_card_size().y*Game::get_scale()/2);
And then in my Deck class which behaves like std::stack of Cards I use function:
void Deck::push(const Card& crd)
{
push_back(crd);
..//
std::default_random_engine generator;
std::uniform_real_distribution<float> distributor(0,360);
top().setRotation(distributor(generator));
}
Card::setRotaion() looks like this, (which stil rotates card around top left corner) :
void Card::setRotation(float angle)
{
card_sprite.setRotation(angle);
}
Thanks for help in advance
Edit: Actually most methods in sf::Transform accept extra arguments to specify a center for the transformation, as per https://stackoverflow.com/users/7703024/super 's comment on my question on the same theme : How to "set the origin" of a Transform in sfml
I'm not too sure from your code, but I might've come up against a similar problem.
I "solved" it (in a very not ideal way) by replacing every call to a sfml drawing function with a call to a custom function when using sf::Transforms.
eg: instead of doing something like:
window.draw(thing, my_transform);
I had to do :
draw_transformed(thing, my_transform, window)
Where the code of draw_transformed looks like this:
void draw_transformed (sf::Shape const& thing, sf::Transform const& t, sf::RenderWindow& window) // cf note (1)
{
sf::Vector2f pos = thing.getPosition();
sf::Transform go_to_zero;
go_to_zero.translate(-pos);
sf::Transform go_back;
go_back.translate(pos);
sf::Transform conjugated_transform = go_back * t * go_to_zero ;
window.draw(thing, conjugated_transform);
}
(1) we can't use sf::Drawable as the type of thing because in sfml not all drawable things have a getPosition method, so we have to overload the function or do something "complicated" to go beyond this example.
I just started programming with SFML, I'm trying to make something shoot a bullet. Currently I have made the bullet move one way when I press space. But I cannot shoot multiple bullets at the same time, it just uses the same image. I can't figure out what I should do, if I should give each bullet it's own name?
Also should I delete it when it's out from the window? If I should how can I do it?
Here's the relevant code:
void Game::handleWeaponInput(sf::Keyboard::Key key, bool isPressed)
{
if (key == sf::Keyboard::Space)
{
mIsFired = isPressed;
if (!mBulletTexture.loadFromFile("Media/Textures/Bullet.png"))
{
}
mBullet.setTexture(mBulletTexture);
mBullet.setPosition(100.f, 100.f);
mBullet.setRotation(90.f);
}
}
And:
void Game::update(sf::Time elapsedTime)
{
sf::Vector2f bulletMovement(0.f, 0.f);
if (mIsFired)
bulletMovement.x += 300.f;
mBullet.move(bulletMovement * elapsedTime.asSeconds());
}
One thing you can do is create a std::vector of bullets so you can track each one individually.
class Game
{
sf::Texture mBulletTexture;
// declare a std::vector of bullets
std::vector<sf::Sprite> mBullets;
public:
void handleWeaponInput(sf::Keyboard::Key key, bool isPressed);
void update(sf::Time elapsedTime);
};
void Game::handleWeaponInput(sf::Keyboard::Key key, bool isPressed)
{
if (key == sf::Keyboard::Space)
{
mIsFired = isPressed;
if (!mBulletTexture.loadFromFile("Media/Textures/Bullet.png"))
{
}
mBullets.emplace_back(); // add another sf::Sprite to vector
mBullets.back().setTexture(mBulletTexture);
mBullets.back().setPosition(100.f, 100.f);
mBullets.back().setRotation(90.f);
}
}
void Game::update(sf::Time elapsedTime)
{
sf::Vector2f bulletMovement(0.f, 0.f);
if (mIsFired)
bulletMovement.x += 300.f;
// move each bullet in the vector
for(auto& bullet: mBullets)
bullet.move(bulletMovement * elapsedTime.asSeconds());
}
Obviously this exact code won't work properly as you will also have to manage how each bullet moves (what direction etc....). But hopefully it will give you an idea how you could scale from one bullet to many bullets.
It may be worth defining a class Bullet that contains the sf::Sprite along with information about the bullet's speed and direction?
Then you could make your vector with those:
class Bullet
{
sf::Sprite sprite;
sf::Texture texture;
sf::Vector2f direction;
public:
// ...
};
class Game
{
// declare a std::vector of bullets
std::vector<Bullet> mBullets;
// ...
};
first of all, I want to tackle your update method: You should update each existing bullet each frame independently of whether you fired one or not:
void Game::update(sf::Time elapsedTime) {
sf::Vector2f bulletMovement(300.f, 0.f);
for (auto& bullet : mBullets) // range-based-for and auto require C++11
bullet.move(bulletMovement * elapsedTime.asSeconds());
}
As others have already suggested, for a simple use case, a vector of bullets works nicely. If you need more complex data structures to handle your game entities, try researching on things like "scene graph" or "quad tree".
std::vector<sf::Sprite> mBullets;
to add a bullet, simply use
// possibly construct sprite seperatly and add some transforms beforehand
mBullets.push_back(sf::Sprite(/* however you store your texture */));
And yes, it is a good idea to destroy bullets once they are outside of your screen, since you would be wasting draw calls and other operations on entities which you will never see again. Using the tools SFML already provides, one could do it like this:
void Game::destroyBulletsOutsideView() {
sf::FloatRect viewBounds(0, 0, mWindow.getSize().x, mWindow.getSize().y);
for (auto iter = mBullets.begin(); iter != mBullets.end(); ++iter) {
if (!viewBounds.intersects(iter->getGlobalBounds())
mBullets.erase(iter);
}
}
Side note: You will likely want to add something like a reload or cooldown time to your Bullets, so you can't shoot tons of bullets per second.
I have a texture and sprite in a base class that is being extended by another class, however when drawn, the sprite displays as a white box. I know this is something to do with the sprite losing it's link to the texture object, but I'm kind of new to C++, so I'm not really sure how it happened.
Here is the code (I've removed some of the irrelevant parts to cut down the size):
Pickup.h:
#ifndef PICKUPS_PICKUP_H
#define PICKUPS_PICKUP_H
#include <SFML\Graphics.hpp>
#include "..\Player.h"
namespace Pickups
{
class Pickup
{
private:
sf::Vector2f position;
sf::Texture texture;
sf::Sprite sprite;
public:
Pickup();
bool drop(float dt);
void draw(sf::RenderWindow* window);
void setTexture(sf::String name);
void setPos(sf::Vector2f position);
sf::Vector2f getPos();
void isColliding(Player* player);
virtual void onCollect(Player* player) = 0;
};
}
#endif
pickup.cpp:
#include "Pickup.h"
namespace Pickups
{
Pickup::Pickup()
{
}
void Pickup::draw(sf::RenderWindow* window)
{
window->draw(sprite);
}
void Pickup::setTexture(sf::String name)
{
if (!texture.loadFromFile("images/pickups/" + name + ".png"))
std::cout << "Error loading image: images/pickups/" + name.toAnsiString() + ".png" << std::endl;
else
sprite.setTexture(texture);
}
}
Health.h:
#ifndef PICKUPS_HEALTH_H
#define PICKUPS_HEALTH_H
#include "Pickup.h"
namespace Pickups
{
class Health : public Pickup
{
private:
int worth;
public:
Health(sf::Vector2f position, int worth);
void onCollect(Player* player);
};
}
#endif
health.cpp:
#include "Health.h"
namespace Pickups
{
Health::Health(sf::Vector2f position, int worth)
{
setTexture("health");
setPos(position);
this->worth = worth;
}
void Health::onCollect(Player* player)
{
player->addLives(worth);
}
}
(I don't know if this is part of the problem, but I might as well post it too)
I store the pickups in a vector like so:
std::vector<Pickups::Health> pickups;
A std::vector copies or moves the inserted elements, so as long as you have the default copy constructor or as long as you do not change this dirty a texture per element-style, (the elements just need to have one common texture object to actually point to, so you waste much much memory) the pointer that the sf::Sprite object holds to the texture gets invalid. To see why we need to think whats happens on insertion:
You setup a nice Pickupish object and add it to the vector which calls the copy-constructor. Lets say your nice object that you wanted to add is object A and the now added/copied object is B. Both have a sprite S and a texture T. Both textures are valid, but the problem is this: A's S points to A's T, so after copying it to B B's S points also to A's T! As I assume A is just temporary so it gets destructed, together with its texture, and there you have it, a nice white box.
You can solve this in some other dirty ways like making your own copy-constructor in Pickup like this:
Pickup::Pickup(const Pickup& other)
: position(other.position), texture(other.texture), sprite(other.sprite)
{ sprite.setTexture(texture); }
or by storing std::unique_ptr<Pickups::Health>'s and not just Pickups::Health's.
However a much better way you should use is some kind of Resourcemanager, which just stores all relevant textures, ideally one, a big tileset, because loading once but big is faster than loading multiple but small textures. You can write your own very simple manager or use some other e.g. the one from the great Thor library. To set a specific tile as texture for a Sprite just call sf::Sprite::setTextureRect.
I want to mention some additional improvements to your design. Let Pickup derive from sf::Drawable and define its pure virtual draw function, which you can make private. Thus your from Pickup deriving object doesn't need to know from any sf::RenderTarget and you can just do target.draw(myPickupObject).
There is no need to store the position, just let Pickup derive from sf::Transformable, too. You don't have to implement any functions, the only thing you need to do is applying the matrix to the sf::RenderStates object thats passed to draw.
Overall your draw function might look like this:
void Pickup::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
//'applying' transformation-matrix
states.transform *= getTransform();
target.draw(sprite, states);
}
So your Pickup has now only sf::Sprite as member and overall your header just needs to include SFML/Graphics/Sprite.hpp.
For avoid this type of problem I always declare my Texture as a pointer and deleting it in the destructor of the class. Like this your Texture will always exist whenever your object is not destroyed.
And it's always good to verify the loading of the image :
if (!texture.loadFromFile("images/pickups/health.png")){
//some error code
}
But it's not the problem here.
I am trying to make a simple function or class that selects an image and returns it or passes it in some way to a different class. Is it as simple as knowing what type the Image is considered? or do I need to do something else? I am running Code::Blocks 10.05 with GNU GCC compiler on a windows 8 computer. Any help is appreciated.
Thanks to Aesthete, I made some progress. Now I have this:
class Background{
sf::Image BGI;
sf::Sprite BG;
Image& img;
public:
void rimage(std::string name){
sf::Image extra;
extra.LoadFromFile(name);
img = extra;
}
void init(std::string name){
BGI = img
BG.SetPosition(0.f,0.f);
BG.SetImage(BGI);
}
};
But when I run it, I get this:
...4 error: ISO C++ forbids declaration of 'Image" with no type
Also,
...10 error: 'img' is defined in this scope
I have included the libraries that I need to run SFML, I just left it out to keep things clean, I adjusted the lines the errors above occurred on to make it easier to follow.
Isn't img now sort of a global variable within Background?
and I thought Image& was the type of img... What needs to change here?
You don't need a load method, nor any extra Image objects. You can do all this processing in the constructor.
class Background{
private:
// You only need an image and a background, if that.
sf::Image BGI;
sf::Sprite BG;
public:
// Use a constructor.
Background(std::string name)
{
SetBackground(name, Vector2f(0.f, 0.f));
}
void SetBackground(std::string name, sf::Vector2f pos)
{
BGI.LoadFromFile(name);
BG.SetImage(BGI);
BG.SetPosition(pos);
}
};
// Constructor loads image, sets image to sprite, and set sprite position.
Background bg("MyBackground.png");
// You can change the background image an position like so.
bg.SetBackgrond("newImage.png", Vector2f(10.f, 20.f));