SFML Collisions never register in my system - c++

Trying to make a collision system in sfml for the first time in SFML without using a tutorial, using a array-based thing like so:
bool moright, moleft, moup, xcollision, ycollision;
float xvel, yvel;
int position, predictx, predicty, cm, arraynum;
class playerClass{
public:
playerClass(){
}
void update()
{
if (moright == true){
xvel = 2;}
if (moleft == true){
xvel = -2;}
if (!(moright || moleft)){
if (xvel < 0)
xvel = 0;
if (xvel > 0)
xvel = 0;}
}
};
int main()
{
playerClass playerObject;
// Create the main window
RenderWindow window(VideoMode(1080, 720), "SFML window");
// Load a sprite to display
Texture texture;
if (!texture.loadFromFile("gsquare100x100.png"))
return EXIT_FAILURE;
Sprite sprite(texture);
Sprite floor(texture);
Sprite wall(texture);
floor.setPosition(Vector2f(0.f, 498.f));
wall.setPosition(Vector2f(598.f,0.f));
floor.setColor(Color(0, 255, 0));
floor.setScale(12.f, 12.f);
wall.setScale(12.f, 12.f);
wall.setColor(Color(0, 0, 255));
int collisions[2][4]{
{0, 400, 500, 600},
};
// Start the game loop
while (window.isOpen())
{
Vector2f position = sprite.getPosition();
cout << position.y << endl;
predictx = position.x + xvel;
predicty = position.y + yvel;
yvel = 1;
for (arraynum = 0; arraynum < 2; arraynum++){
if ((predictx > collisions[arraynum][0])&&(predictx < collisions[arraynum][1])&&(predicty > collisions[arraynum][2])&&(predicty < collisions[arraynum][3])){
if ((position.y > collisions[arraynum][3])||(position.y < collisions[arraynum][2])){
xcollision = true;}
if ((position.x > collisions[arraynum][1])||(position.x < collisions[arraynum][0])){
ycollision = true;}
}
}
if (xcollision == true)
xvel = 0;
xcollision = false;
if (ycollision == true)
yvel = 0;
ycollision = false;
sprite.move(sf::Vector2f(0.f+xvel, 0.f+yvel));
// Process events
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == Event::KeyPressed)
{if (event.key.code == Keyboard::D)
moright = true;
if (event.key.code == Keyboard::A)
moleft = true;}
if (event.type == Event::KeyReleased)
{if (event.key.code == Keyboard::D)
moright = false;
if (event.key.code == Keyboard::A)
moleft = false;}
playerObject.update();
}
However the collision never registers, removing the bit that checks from which direction the sprite is moving in from doesn't help.
Very new to c++ so apologies if this is a stupid question and for my likely overly elaborate collision system.

I've written simple collisions with SFML before, and here's my advice to you: make your code as readable as possible! Things are going to get more complicated, and you need to have a system is reusable and easy to understand.
I've read your code but I don't understand why you've used an array. I assume you're trying to check if a smaller rectangle sprite is about to exit the collisions array?
For this purpose I suggest using a FloatRect object. It has useful functions like .contains() and .intersects() that you might need in the future. One downside it that is has top and left only, and to make it more and short, we'll define a simple struct to handle that part for us, as well as work for rectangular sprites as well.
I've left comments that explain the code, but haven't tested it personally. You can do that and integrate what you've learned into your project. Good luck
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
using namespace sf;
//using a struct is not necessarily faster. BUT it does give your code more readability and is reusable for future needs
//this struct just stores a floatRect of the given sprite/Floatrecct, defining some useful functions allowing for shorter code and more readability
struct rectangularShape
{
FloatRect containingRectangle;
//constructor with sprite input
rectangularShape(Sprite sprite)
{
this -> containingRectangle = FloatRect(Vector2f(sprite.getGlobalBounds().left, sprite.getGlobalBounds().top),
Vector2f(sprite.getGlobalBounds().left + sprite.getGlobalBounds().width,sprite.getGlobalBounds().top + sprite.getGlobalBounds().height));
}
//constructor with floatrect
rectangularShape(FloatRect rect)
{
this -> containingRectangle = rect;
}
//any useful functions for rectangular shapes-- you could add more if you want
float getTop() {return containingRectangle.top;}
float getbottom() {return containingRectangle.top + containingRectangle.height;}
float getleft() {return containingRectangle.left;}
float getright() {return containingRectangle.left + containingRectangle.width;}
};
//note the use of a FloatRect instead of the arrays you were using, this just makes it easier to understand
FloatRect inclusionArea(TopLeftVector, BottomRightVector);
Sprite sprite(texture);
//declare rectangularShapes, here we check if smallRectangle is exiting it's container
rectangularShape containingRectangle(inclusionArea);
rectangularShape smallRectangle(sprite);
//alternatively you can use the sprite's next position:
/*
spriteCopy = sprite;
spriteCopy.move(deltaTime * Vector2f(xSpeed, ySpeed));
rectangularShape smallRectangle(spriteCopy);
*/
//do the check:
if (smallRectangle.getTop() < containingRectangle.getTop() or smallRectangle.getBottom() > containingRectangle.getBottom())
//exiting in Y axis
//do something;
;
if (smallRectangle.getLeft() < containingRectangle.getLeft() or smallRectangle.getRight() > containingRectangle.getRight())
//exiting in X axis
//do something;
;

I can't comment due to low reputation.
From the code presented, it's seems like you never set xcollision or ycollision to true anywhere.

Related

Why setPosition work in some condition but doesn't work in other condition?

i make a game let's say ThrowBall, the Player can pick up the ball spawned and throw it into target get the score added then the ball return it's position and repeat. The problem is when Ball dragged by Player (i make the Ball as child of Player) into target, the Ball return it's position correctly into desired position, but the odd happens when it collided after i send the Ball into target by applying impulse it won't return the ball into desired position, why is this happening?
i'm running this game for android, i'm running this code in VS'17 using cocos2d-x-3.17. I tried changing impulse into force, moveby. I tried making the ball stop (setVelocity to zero before setPosition). I tried changing Point into Vect, vec2. I tried to break point debug, the code do read setPosition but do nothing.
GameScene.cpp
bool GameScene::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto pickupListener = EventListenerPhysicsContact::create();
pickupListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(pickupListener, this);
return true;
}
bool GameScene::onContactBegin(cocos2d::PhysicsContact &contact)
{
PhysicsBody *a = contact.getShapeA()->getBody();
PhysicsBody *b = contact.getShapeB()->getBody();
if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
// make the ball follow Player
isfollow = true;
}
else if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && TARGET_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && TARGET_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
isfollow = false;
// add score
score++;
__String *tempScore = __String::createWithFormat("%i", score);
scoreLabel->setString(tempScore->getCString());
// return spawn ball
ball->returnPos();
return false;
}
void GameScene::throwBall() {
if (isfollow == true) {
isfollow = false;
ball->getSprite()->getPhysicsBody()->applyImpulse(Vec2(100000, 100000));
}
}
Ball.h
class Ball
{
public:
Ball(cocos2d::Layer *layer);
cocos2d::Sprite *getSprite() { return randomSpawn; };
void returnPos();
private:
cocos2d::Size visibleSize;
cocos2d::Vec2 origin;
cocos2d::Sprite *randomSpawn;
};
Ball.cpp
Ball::Ball(cocos2d::Layer *layer)
{
visibleSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
randomSpawn = Sprite::create("res/ball.png");
randomSpawn->setPosition(Vec2(400, 80));
auto randomBallBody = PhysicsBody::createCircle(randomSpawn->getContentSize().width / 2);
randomBallBody->setCollisionBitmask(BALL_COLLISION_BITMASK);
randomBallBody->setContactTestBitmask(true);
randomBallBody->setGravityEnable(false);
randomSpawn->setPhysicsBody(randomBallBody);
layer->addChild(randomSpawn);
}
void Ball::returnPos()
{
randomSpawn->setPosition(Vec2(400, 80));
}
i want to make the object (Ball) return position when collided into Target and repeat. i'm sorry if the format is a mess, i'm new here, also it's not my full code, it's actually works fine i can run it, but only the setPosition won't work

Write text input on the screen in SFML

So I'm creating a graphing calculator. I have an input string s. From the string, I can graph it using SFML. I start from the a MIN x-coordinate to a MAX x-coordinate, get the corresponding y from a EvaluateString() method, and all the coordinates to a VertexArray v. I wrote my method and the graphing method already and it all worked well.
However, I have a small issue. I want to input my string on the screen, such as "sin(cos(tan(x)))" like this. I'm struggling to find a way to do it. I kinda figured out it has to do with the event TextEntered, but still I can't find anything completely.
Please suggest me a way.
class Calculator{
public:
void main();
private:
WindowSize DefaultWindow;
sf::RenderWindow window;
Cartesian vertexX[2],vertexY[2];
sf::Vertex axis[4];
const double MAX = 10;
const double MIN = -10;
const double INCREMENT = 0.001;
};
int main(){
DefaultWindow.Max = Cartesian(10,10);
DefaultWindow.Min = Cartesian(-10,-10);
DefaultWindow.plane.width=1500;
DefaultWindow.plane.height=1500;
// Set up x and y-axis
vertexX[0] = Cartesian(-100,0);
vertexX[1] = Cartesian(100, 0);
vertexY[0] = Cartesian(0,-100);
vertexY[1] = Cartesian(0,100);
axis[0] = sf::Vertex(convertCartesiantoWindow(vertexX[0],DefaultWindow));
axis[1] = sf::Vertex(convertCartesiantoWindow(vertexX[1],DefaultWindow));
axis[2] = sf::Vertex(convertCartesiantoWindow(vertexY[0],DefaultWindow));
axis[3] = sf::Vertex(convertCartesiantoWindow(vertexY[1],DefaultWindow));
// Set up the window
window.create(sf::VideoMode(1500, 1500), "Graphing calculator");
// Input string
string s = "sin(cos(tan(x)))";
// Stack c contains all the Cartesian coordinate vertices
// Cartesian is a struct which contains x and y coordinates
Stack<Cartesian> c;
sf::VertexArray v;
// For a certain function in string s, I evaluate it
// and return the y_coordinate from the function EvaluateString (s, i)
// Push each (x,y) evaluated in the Stack c
for (double i = MIN; i <= MAX; i+= INCREMENT)
c.Push(Cartesian(i,EvaluateString(s,i)));
// v is VertexArray which contains all the vertices (x,y)
v = plot(DefaultWindow, c);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
}
}
}
// Draw the graph
window.clear(sf::Color::Black);
window.draw(axis,4,sf::Lines);
window.draw(v);
window.display();
}
As #super suggest, use a library would be a nice solution, and surely better than mine, but just in case this satisfies your needs, I implemented a super basic TextField class.
It may be plenty of errors, but it can gives you an idea on how to achieve that functionality.
A TextField is nothing more than a rectangle which contains a text. Since it will have a sf::Text, it must have a sf::Font. Additionally, I limit the number of characters that it will contain. In order for us to write inside the TextField, we have to know if it's selected, i.e. if it has the focus. So, a first approach could be:
class TextField : public sf::Transformable, public sf::Drawable{
private:
unsigned int m_size;
sf::Font m_font;
std::string m_text;
sf::RectangleShape m_rect;
bool m_hasfocus;
};
We need a constructor for this class:
class TextField : public sf::Transformable, public sf::Drawable{
public:
TextField(unsigned int maxChars) :
m_size(maxChars),
m_rect(sf::Vector2f(15 * m_size, 20)), // 15 pixels per char, 20 pixels height, you can tweak
m_hasfocus(false)
{
m_font.loadFromFile("C:/Windows/Fonts/Arial.ttf"); // I'm working on Windows, you can put your own font instead
m_rect.setOutlineThickness(2);
m_rect.setFillColor(sf::Color::White);
m_rect.setOutlineColor(sf::Color(127,127,127));
m_rect.setPosition(this->getPosition());
}
private:
unsigned int m_size;
sf::Font m_font;
std::string m_text;
sf::RectangleShape m_rect;
bool m_hasfocus;
};
We also need some basic methods, we want to get the text inside:
const std::string sf::TextField::getText() const{
return m_text;
}
and move it, placing it somewhere inside our window:
void sf::TextField::setPosition(float x, float y){
sf::Transformable::setPosition(x, y);
m_rect.setPosition(x, y);
}
this is a tricky one. We are overwritting setPosition method of sf::Transformable because we need to update our own m_rect.
Also, we need to know if a point is inside of the box:
bool sf::TextField::contains(sf::Vector2f point) const{
return m_rect.getGlobalBounds().contains(point);
}
pretty simple, we use cointains method of sf::RectangleShape, already in sfml.
Set (or unset) focus on the TextField:
void sf::TextField::setFocus(bool focus){
m_hasfocus = focus;
if (focus){
m_rect.setOutlineColor(sf::Color::Blue);
}
else{
m_rect.setOutlineColor(sf::Color(127, 127, 127)); // Gray color
}
}
easy one. For aesthetics, we also change the outline color of the box when focused.
And last, but not least, our TextField has to behave some way when input (aka an sf::Event) is received:
void sf::TextField::handleInput(sf::Event e){
if (!m_hasfocus || e.type != sf::Event::TextEntered)
return;
if (e.text.unicode == 8){ // Delete key
m_text = m_text.substr(0, m_text.size() - 1);
}
else if (m_text.size() < m_size){
m_text += e.text.unicode;
}
}
That delete key check is little dirty, I know. Maybe you can find better solution.
That's all! Now main looks like:
int main()
{
RenderWindow window({ 500, 500 }, "SFML", Style::Close);
sf::TextField tf(20);
tf.setPosition(30, 30);
while (window.isOpen())
{
for (Event event; window.pollEvent(event);)
if (event.type == Event::Closed)
window.close();
else if (event.type == Event::MouseButtonReleased){
auto pos = sf::Mouse::getPosition(window);
tf.setFocus(false);
if (tf.contains(sf::Vector2f(pos))){
tf.setFocus(true);
}
}
else{
tf.handleInput(event);
}
window.clear();
window.draw(tf);
window.display();
}
return 0;
}
Proof of concept:
std::string str;
sf::String text;
// In event loop...
if (event.Type == sf::Event::TextEntered)
{
// Handle ASCII characters only
if (event.Text.Unicode < 128)
{
str += static_cast<char>(event.Text.Unicode);
text.SetText(str);
}
}
// In main loop...
window.Draw(text);
This should create an sf::Event::TextEntered for input, and sf::String for output

SFML C++11 Trying to call a function in an object which is in a vector

So I am trying to make a simple shooter but so far i had no luck. I want to spawn bullets when the user presses right shift. And the bullets should fire at the top of the screen. The bullets do spawn but they dont move.
I created a vector to hold the created bullets named "bullets". Then I used the update function in my core struct to detect RShift presses and push an instance of the Bullet object to the vector.
Later on in my main class I iterate the vector and draw the bullets. But when I try calling the function it doesnt work.
My Code so far:
#include <SFML/Graphics.hpp>
#include <stdio.h>
const unsigned int ResX{480}, ResY{640};
struct Bullet {
sf::CircleShape shape;
Bullet(float sX, float sY, sf::Color color, float bullet_radius) {
shape.setRadius(bullet_radius);
shape.setOrigin(bullet_radius, bullet_radius);
shape.setFillColor(color);
shape.setPosition(sX, sY);
}
void update(float vel) {
sf::Vector2f velocity;
velocity.y = -abs(vel);
shape.move(velocity);
}
};
std::vector<Bullet> bullets;
struct Core {
const float core_width{64}, core_height{48}, core_velocity{0.2};
sf::RectangleShape shape;
sf::Vector2f velocity;
Core(float sX, float sY) {
shape.setSize({core_width, core_height});
shape.setPosition(sX, sY);
shape.setFillColor(sf::Color::White);
shape.setOrigin(core_width/2, core_height/2);
}
void update() {
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
velocity.x = -core_velocity;
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
velocity.x = core_velocity;
else
velocity.x = 0;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
velocity.y = -core_velocity;
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
velocity.y = core_velocity;
else
velocity.y = 0;
shape.move(velocity);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::RShift)) {
Bullet b(shape.getPosition().x, shape.getPosition().y, sf::Color::Red, 5);
bullets.push_back(b);
}
}
};
int main(int argc, char *argv[])
{
sf::RenderWindow window(sf::VideoMode(ResX, ResY), "Brick Breaker", sf::Style::None);
Core core(ResX / 2, ResY /2 + 200);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
window.close();
}
std::printf("VelocityX=%f, BulletVelocity=\n",core.velocity.x);
window.clear();
core.update();
window.draw(core.shape);
for(const auto& b : bullets)
window.draw(b.shape);
//this function is causing an error : method update could not be resolved!
b.update();
window.display();
}
return 0;
}
btw i feel the need to say i am very very unexperienced with programming in c++ I am a complete beginner so any advice is welcome. srry 4 bad english. thanks!
EDIT: I figured it out thx! (The problem was that i missed the curly brackets:
for(const auto& b : bullets)
{
window.draw(b.shape);
//this function is causing an error : method update could not be resolved!
b.update();
}
But i have another question aswell! It would be awesome if one of you explained how the iterator functions and what purpose the auto& and const keywords serve here. Thanks again!

Implementing collision response, current implementation does too many checks

I don't know how I should handle my collision response when collision between two entities leads to second collision with third entity.
Blue arrow is velocity of the rightmost entity and numbers below are single collision response.
Single Collision
At the beginning leftmost and middle entities are not colliding with each others, but after rightmost entity collides with middle one, the velocity middle entity gains now causes it to collide with leftmost one
How end result should be
Or if the leftmost entity was a wall -> 0, 0, -v
Current implementation: check collisions until all are handled
Velocities before collision handling
0, 0, <-10
Collisions: 2&3
If entity velocity is changed due the collision do new check
After 1. collision check:
0, <-5, <-5
Collisions: 1&2
After 2. collision check:
<-2.5, <-2.5, <-5
Collisions: 2&3
After 3. collision check:
<-2.5, <-3.75, <-3.75
Collisions: 1&2
After 4. collision check:
<-3.125, <-3.125, <-3.75
Collisions: 2&3
After nth collision check:
<-3.33, <-3.33, <-3.33
No collisions
Continue
Question: As we clearly see, it takes way too many collision checks to fix even simple collisions this way. How should I improve this?
Sample code written with sfml:
I have 3 types of entities in my test case:
wall
pushable
passable
Entity, velocity and boundingRect:
Collision response:
wall <-> pushable: can't move inside wall, push pushable entity away
pushable <-> pushable: both are repelled from each others so they won't collide
wall<->wall: skip collision checks between walls and all checks with passable terrain
Controls in sample code
Arrow keys: move green entity
Left mouse button: spawn pushable entities
Right mouse button: spawn wall entities
Middle mouse button: spawn moving pushable entities
.
#include <SFML/Graphics.hpp>
#include <iostream>
const sf::Vector2f entitySize(16.f, 16.f);
bool isMovingUp = false;
bool isMovingDown = false;
bool isMovingRight = false;
bool isMovingLeft = false;
enum Category
{
wall,
pushable,
passable,
};
class Entity
{
public:
Entity(sf::Vector2f position, sf::Color color, Category type) : position(position), type(type)
{
shape.setSize(entitySize);
shape.setFillColor(sf::Color::Transparent);
shape.setOutlineColor(color);
shape.setOutlineThickness(1.f);
}
sf::Vector2f position;
sf::Vector2f velocity;
sf::Vector2f adjustedVelocity;
sf::Vector2f defaultVelocity;
sf::RectangleShape shape;
Category type;
};
void DrawEntity(sf::RenderWindow& window, Entity& entity)
{
entity.shape.setPosition(entity.position - entity.shape.getSize() / 2.f);
window.draw(entity.shape);
}
sf::FloatRect GetBoundingRect(const Entity& entity)
{
return sf::FloatRect(entity.position+entity.velocity - entitySize / 2.f, entitySize);
}
void HandleCollision(std::vector<Entity>& entities)
{
bool allCollisionsChecked = false;
while(!allCollisionsChecked)
{
allCollisionsChecked = true;
// Pair all possible combinations, but only once per pair
for (auto first = entities.begin(); first != entities.end(); ++first)
{
for (auto second = std::next(first); second != entities.end(); ++second)
{
if (first->type == Category::passable || second->type == Category::passable || first->type == Category::wall && second->type == Category::wall)
continue;
sf::FloatRect intersection;
if (GetBoundingRect(*first).intersects(GetBoundingRect(*second), intersection))
{
if (second->position == first->position)
second->position.x += entitySize.x;
sf::Vector2f direction = second->position - first->position;
sf::Vector2f offset;
// X collision
if (abs(direction.x) > abs(direction.y))
offset.x = ((direction.x<0)?-1:1)*intersection.width;
// Y collision
if (abs(direction.x) < abs(direction.y))
offset.y = ((direction.y<0)?-1:1)*intersection.height;
if(first->type == Category::pushable && second->type == Category::pushable)
{
first->velocity -= offset / 2.f;
second->velocity += offset / 2.f;
allCollisionsChecked = false;
}
else if(first->type == Category::pushable)
{
first->velocity -= offset;
allCollisionsChecked = false;
}
else if(second->type == Category::pushable)
{
second->velocity += offset;
allCollisionsChecked = false;
}
}
}
}
}
}
void handlePlayerInput(sf::Keyboard::Key key, bool isPressed)
{
switch(key)
{
case sf::Keyboard::Up:
isMovingUp = isPressed;
break;
case sf::Keyboard::Down:
isMovingDown = isPressed;
break;
case sf::Keyboard::Left:
isMovingLeft = isPressed;
break;
case sf::Keyboard::Right:
isMovingRight = isPressed;
break;
}
}
int main()
{
sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Application");
window.setVerticalSyncEnabled(true);
std::vector<Entity> entities;
Entity player(sf::Vector2f(1280/2, 720/2), sf::Color::Green, Category::pushable);
entities.push_back(player);
size_t cols = 1280/int(entitySize.x);
size_t rows = 720/int(entitySize.y);
for (size_t i=0; i < cols*rows; ++i)
if (i%cols == rows/5 && i/cols > rows/6 && i/cols < rows*5/6 || i%cols >= rows/5 && i%cols <= rows*4/5 && (i/cols == rows/6 || i/cols == rows*5/6))
entities.push_back(Entity(sf::Vector2f(entitySize.x*(i%cols)+entitySize.x/2, entitySize.y*(i/cols)+entitySize.y/2), sf::Color::Yellow, Category::wall));
//else
//entities.push_back(Entity(sf::Vector2f(entitySize.x*(i%cols)+entitySize.x/2, entitySize.y*(i/cols)+entitySize.y/2), sf::Color::Transparent, Category::passable));
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::MouseButtonPressed)
{
sf::Vector2i pixel(event.mouseButton.x, event.mouseButton.y);
sf::Vector2f coord = window.mapPixelToCoords(pixel);
if (event.mouseButton.button == sf::Mouse::Left)
{
Entity pushable(coord, sf::Color::Blue, Category::pushable);
entities.push_back(pushable);
}
else if (event.mouseButton.button == sf::Mouse::Right)
{
Entity wall(coord, sf::Color::Yellow, Category::wall);
entities.push_back(wall);
}
else if (event.mouseButton.button == sf::Mouse::Middle)
{
Entity mover(coord, sf::Color::Magenta, Category::pushable);
mover.defaultVelocity.x = -1.f;
entities.push_back(mover);
}
}
switch (event.type)
{
case sf::Event::KeyPressed:
handlePlayerInput(event.key.code, true);
break;
case sf::Event::KeyReleased:
handlePlayerInput(event.key.code, false);
break;
case sf::Event::Closed:
window.close();
break;
}
}
if (isMovingUp)
entities[0].velocity.y -= 5.f;
if (isMovingDown)
entities[0].velocity.y += 5.f;
if (isMovingLeft)
entities[0].velocity.x -= 5.f;
if (isMovingRight)
entities[0].velocity.x += 5.f;
if (entities[0].velocity.x != 0.f && entities[0].velocity.y != 0.f)
{
entities[0].velocity.x /= std::sqrt(2.f);
entities[0].velocity.y /= std::sqrt(2.f);
}
HandleCollision(entities);
// Apply and reset velocities
for (Entity& e : entities)
{
e.position += e.velocity;
e.velocity = e.defaultVelocity;
}
// Draw
window.clear();
for (Entity& e : entities)
DrawEntity(window, e);
window.display();
}
}
Sample results
Magenta entities are moving to the left with constant speed and yellow entities are wall.
without checking collisions due the other collisions
Desired outcome:
Same scenario when checking collisions until all are resolved
How could I achieve this?

SFML Sprite moving violently down on 2nd tick

I am working on an SFML game and for some reason after spawning the player, the player gets teleported down. On the first tick he is correctly positioned, but after wards, he is moved down. Any idea on how to diagnose this problem? I set up breakpoints in the move mechanism, the only place where the player's co-ordinates change, and it seems to happen right after the function ends. This is the main function:
int main(){
App.ShowMouseCursor(false);
mainch.mainchinventory.read();
while (App.IsOpened())
{
sf::Event Event;
while (App.GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
App.Close();
}
float time = App.GetFrameTime();
mainch.move(time);
App.Clear();
drawall();
App.Display();
}
return EXIT_SUCCESS;
}
Mainch.move(t):
void cmainchar::move(float t){
if (App.GetInput().IsKeyDown(sf::Key::S)) mainchinventory.save();
if (App.GetInput().IsKeyDown(sf::Key::R)) mainchinventory.read();
if (App.GetInput().IsKeyDown(sf::Key::A)) A = true;
else A = false;
if (App.GetInput().IsKeyDown(sf::Key::D)) D = true;
else D = false;
if(grounded)
if (App.GetInput().IsKeyDown(sf::Key::W)) first = true;
if ((App.GetInput().IsKeyDown(sf::Key::I)) && (keyreleased)){
if (mainchinventory.drawmain){
mainchinventory.drawmain = false;
mainchinventory.press(mainchinventory.selectionx, 3);
}
else{
mainchinventory.drawmain = true;
}
keyreleased = false;
}
else if (!App.GetInput().IsKeyDown(sf::Key::I))
keyreleased = true;
if(!mainchinventory.drawmain){
if(App.GetInput().IsKeyDown(sf::Key::Num1)) mainchinventory.press(0, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num2)) mainchinventory.press(1, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num3)) mainchinventory.press(2, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num4)) mainchinventory.press(3, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num5)) mainchinventory.press(4, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num6)) mainchinventory.press(5, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num7)) mainchinventory.press(6, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num8)) mainchinventory.press(7, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num9)) mainchinventory.press(8, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num0)) mainchinventory.press(9, 3);
if(App.GetInput().IsMouseButtonDown(sf::Mouse::Button::Left)){
mainchinventory.dockitems[mainchinventory.selectionx].use();
spells.push_back(cspell());
}
}
else if ((App.GetInput().IsMouseButtonDown(sf::Mouse::Button::Left)) && (mainchinventory.drawmain) && (buttonreleased)){
mainchinventory.checkmouse();
buttonreleased = false;
}
else if (!App.GetInput().IsMouseButtonDown(sf::Mouse::Button::Left))
buttonreleased = true;
int xmap = (View.GetCenter().x - 320) / 40;
int ymap = (View.GetCenter().y - 240) / 40;
if ((xmap != xmapold) || (ymap != ymapold))
maps.read();
xmapold = xmap;
ymapold = ymap;
collisions();
for(std::list<cspell>::iterator i = mainch.spells.begin(); i != mainch.spells.end(); i++)
if (i->move(t))
spells.erase(i);
if (A && left){
animate(2, t);
you.Move(-160 * t, 0);
}
if (D && right){
animate(1, t);
you.Move(160 * t, 0);
}
if (!D && !A)
animate(0, t);
if (up){
if(grounded && first){
jump = 1.25;
first = false;
}
if (jump > 0){
you.Move (0,-250 * t * jump);
jump = jump - 1 * t;
}
if (jump <= 0){
jump = 0.f;
}
}
else{
first = false;
jump = 0.f;
}
if (down){
fall = fall + 10 * t;
you.Move(0, 25 * fall * t);
grounded = false;
}
else{
fall = 0.f;
grounded = true;
}
if(teleport){
mainchinventory.spawn = true;
fall = 0.f;
jump = 0.f;
maps.changemap(maps.nxtmap);
teleport = false;
}
moveview();
}
You don't show the code where you're manipulating the sf::Sprite object, so I (or anyone else, really) can't say for certain, but...that said, I have a strong guess as to what's happening.
I've been familiarizing myself with SFML recently, too, and I encountered this issue myself. What I think is happening is you're calling sf::Sprite::Move(x,y) to move the sprite to position (x,y). This is incorrect; what you should be calling is sf::Sprite::SetPosition(x,y). (Both these functions take will take a 2d vector as an argument instead, btw).
I'm operating under the assumption you're using SFML 1.6, yes? Looks that way...version 2.0 changes the API somewhat, so in case you're using that Sprite::Move() becomes Sprite::move() and Sprite::SetPosition() becomes Sprite::setPosition().
Anyways, to wrap this up: the difference between Move(x,y) and SetPosition(x,y) is that Move adjusts the sprite's position relative to its current position, whereas SetPosition moves the sprite to a new position regardless of where it was before.
Again, this is a blind guess since the relevant code was not included...so was my shot in the dark correct?
Unfortunately, you haven't provided enough code for a straightforward diagnosis. With what you provided however, my best guess is that your fall variable hasn't been initialized. If it hasn't been initialized, its values can be completely random, likely being much larger than expected. This would explain your 'teleporting' behavior.