C++ SFML Collison Detection - c++

I am trying to make a game where you gave to dodge the incoming box (thing). I don't know how to code a quick and easy collision detection using if statements.
I have tried to code this at "//collision detection". I want it so that if the arrow (player) is touching the box the game closes.
Main Menu.h
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
using namespace std;
#pragma once
class main_menu
{
public:
void startmenu(RenderWindow &gameDisplay, Font &font1, bool &MainMenu, RectangleShape &start, Event &evnt)
{
gameDisplay.setMouseCursorVisible(true);
Text starttext;
starttext.setCharacterSize(100);
starttext.setFont(font1);
starttext.setString("DODGE");
starttext.setFillColor(Color(255, 255, 255));
starttext.setStyle(Text::Bold);
FloatRect starttextRect = starttext.getLocalBounds();
starttext.setOrigin(starttextRect.width / 2, starttextRect.height / 2);
starttext.setPosition(Vector2f(1366 / 2.0f - 30, 768 - 700.0f));
RectangleShape outlinetop(Vector2f(1366, 50));
outlinetop.setFillColor(Color(255, 255, 255));
outlinetop.setPosition(0, 0);
RectangleShape outlinebottom(Vector2f(1366, 50));
outlinebottom.setFillColor(Color(255, 255, 255));
outlinebottom.setPosition(0, 718);
RectangleShape outlineright(Vector2f(50, 768));
outlineright.setFillColor(Color(255, 255, 255));
outlineright.setPosition(1316, 0);
RectangleShape outlineleft(Vector2f(50, 768));
outlineleft.setFillColor(Color(255, 255, 255));
outlineleft.setPosition(0, 0);
Text startbuttontext;
startbuttontext.setFont(font1);
startbuttontext.setCharacterSize(70);
startbuttontext.setString("PLAY");
startbuttontext.setFillColor(Color(255, 255, 255));
FloatRect startbuttontextRect = starttext.getLocalBounds();
startbuttontext.setOrigin(starttextRect.width / 2, startbuttontextRect.height / 2);
startbuttontext.setPosition(Vector2f(1366 / 2.0f + 60 - 30, 768 - 480.0f));
if (MainMenu == true)
{
Vector2f tempMouse(Mouse::getPosition(gameDisplay));
if (start.getGlobalBounds().contains(tempMouse) &&
evnt.type == Event::MouseButtonPressed &&
evnt.key.code == Mouse::Left)
{
MainMenu = false;
}
//mouseposx = (Mouse::getPosition(gameDisplay).x);
//mouseposy = (Mouse::getPosition(gameDisplay).y);
/*
while (Mouse::getPosition(gameDisplay).x > 1366 / 2.0 && Mouse::getPosition(gameDisplay).x < 1083)
while (Mouse::getPosition(gameDisplay).y > 768 - 450 && Mouse::getPosition(gameDisplay).y < 868)
if (Mouse::isButtonPressed(Mouse::Left))
MainMenu = false;
*/
if (Keyboard::isKeyPressed(Keyboard::Q))
{
MainMenu = false;
gameDisplay.close();
}
gameDisplay.draw(outlinebottom);
gameDisplay.draw(outlineleft);
gameDisplay.draw(outlineright);
gameDisplay.draw(outlinetop);
gameDisplay.draw(start);
gameDisplay.draw(starttext);
gameDisplay.draw(startbuttontext);
gameDisplay.display();
}
}
};
things.h
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
using namespace sf;
using namespace std;
#pragma once
int RandomXpos = 0;
class Thing
{
public:
void thingspawn(RenderWindow &gameDisplay, int &enemystartx, int &enemystarty, int &enemywidth, int &enemyheight, RectangleShape &thing, int enemyspeed)
{
thing.setFillColor(Color(255,255,255));
if (thing.getPosition().y < 800)
thing.move(0.0f, 0.4f);
if (thing.getPosition().y >= 800)
{
RandomXpos = rand() % 1000;
thing.setPosition(RandomXpos, -200);
}
}
};
main.cpp
#include <iostream>
#include <SFML/Graphics.hpp>
#include "things.h"
#include "Main Menu.h"
#include <cstdlib>
#include <Windows.h>
using namespace std;
using namespace sf;
int main()
{
//FreeConsole();
RenderWindow gameDisplay(VideoMode(1366, 768), "Game", Style::Fullscreen);
gameDisplay.clear();
int enemystarty = -200;
int enemystartx = 300;
int enemyheight = 30;
int enemywidth = 300;
int enemyspeed = 0.3;
int enemycount = 1;
int dodged = 0;
int blockcolor = 0;
bool MainMenu = true;
Font font1;
if (!font1.loadFromFile("OCRAEXT.ttf"))
{
//error...
}
RectangleShape start(Vector2f(400, 100));
start.setFillColor(Color(0, 0, 0));
start.setOutlineThickness(20);
start.setOutlineColor(Color(255, 255, 255));
FloatRect startRect = start.getLocalBounds();
start.setOrigin(startRect.width / 2, startRect.height / 2);
start.setPosition(Vector2f(1366 / 2.0f, 768 - 450.0f));
/*
RectangleShape player(Vector2f(200, 50));
player.setFillColor(Color(0, 0, 255));
player.setPosition(400, 700);
*/
Texture playertexture;
if (!playertexture.loadFromFile("whiter_arrow.jpg"))
{
//error...
}
Sprite player;
player.setTexture(playertexture);
player.setPosition(300, 600);
RectangleShape thing(Vector2f(enemywidth, enemyheight));
thing.setPosition(300, -200);
Event evnt;
while (gameDisplay.isOpen())
{
while (gameDisplay.pollEvent(evnt))
{
switch (evnt.type)
{
case Event::Closed:
gameDisplay.close();
case Event::KeyPressed:
if (Keyboard::isKeyPressed(Keyboard::Q))
gameDisplay.close();
}
}
main_menu object;
object.startmenu(gameDisplay, font1, MainMenu, start, evnt);
while (MainMenu == false)
{
gameDisplay.setMouseCursorVisible(false);
if (Keyboard::isKeyPressed(Keyboard::D))
if (player.getPosition().x < 1200)
{
player.move(0.3f, 0.0f);
}
if (Keyboard::isKeyPressed(Keyboard::A))
if (player.getPosition().x > 50)
{
player.move(-0.3f, 0.0f);
}
if (Keyboard::isKeyPressed(Keyboard::Q))
gameDisplay.close();
Thing thingobject;
thingobject.thingspawn(gameDisplay, enemystartx, enemystarty, enemywidth, enemyheight, thing, enemyspeed);
//collision detection
if (player.getPosition().y <= thing.getPosition().y)
if (player.getPosition().x == thing.getPosition().x)
gameDisplay.close();
gameDisplay.clear();
gameDisplay.draw(player);
gameDisplay.draw(thing);
gameDisplay.display();
}
}
}

There are many ways to do 2D collision detection between sets of objects ("do any of these objects touch each other") and that's beyond the scope of this question. What you seem to be asking is much simpler: "do two 2D rectangles touch?". Let's assume you have rectangles r1 and r2, then you can use:
collision = r1.x <= r2.x + r2.width &&
r2.x <= r1.x + r1.width &&
r1.y <= r2.y + r2.height &&
r2.y <= r1.y + r1.height;
It is also worth noting that in games, you must allow for the possibility of the move increment being too large because of object velocity vs frame rate, allowing objects to appear to move through each other. You can compensate by building bounding rectangles that encompass the before/after positions of both objects and testing that first, before diving into more complex calculations involving the intersection of the swept-through-time volumes.

There is SFML way to do the collision, it will work for your case.
you can do it like this:
if ( player.getGlobalBounds().intersects(thing.getGlobalBounds()) )
{
// player and thing is collided! do something
}
#Wheezil's answer is the standard way to do it, for axis-aligned object like your case. it's better to implement it yourself so you know how it happens :)

Related

sfml gravity clipping shapes through floor

I tried to make a cube that moves side to side and bounces off the floor.
It bounced a couple times and then fell through the floor.
I tried making the floor higher.
I tried adding extra vertical velocity.
I have tried everything i can think of.
I would like to get the cube to not fall through the floor.
how do I do that?
#include <SFML/Graphics.hpp> <iostream>
int main(){
sf::RenderWindow window(sf::VideoMode(1000, 700), "project");
window.setFramerateLimit(60);
sf::RectangleShape rect;
int w = 100;
int h = 100;
rect.setSize(sf::Vector2f(w, h));
sf::Vector2f rectangle_position(500 - (w/2), 300 - (h/2));
rect.setPosition(rectangle_position);
float x_velocity = 3;
float y_velocity = 3;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) window.close();
}
if (rectangle_position.x > 1000 - w) {
x_velocity = x_velocity * -1;
}
if (rectangle_position.x < 1 ) {
x_velocity = x_velocity * -1;
}
if (rectangle_position.y > 700 - h) {
y_velocity = y_velocity * -1;
}
if (rectangle_position.y < 50) {
y_velocity = y_velocity * -1;
}
y_velocity = y_velocity + 3;
rectangle_position.x = rectangle_position.x + x_velocity;
rectangle_position.y = rectangle_position.y + y_velocity;
rect.setPosition(rectangle_position);
window.clear();
window.draw(rect);
window.display();
}
}
In your implementation, once the bottom of the rectangle goes below the ground, you just reverse the velocity but never update the position of the rectangle. This causes the rectangle to sink below the ground.
You should make sure that the bottom of the rectangle never goes below the ground. This can be done by adding the following condition:
if (rectangle_position.y > 700 - h) {
// make sure that rectangle never goes below the ground
rectangle_position.y -= 3;
y_velocity = y_velocity * -1;
}
And the result is:
Hope it helps.

"x is not a class or namespace name" when trying to use functions between namespaces

I am new to C++ and am currently trying to implement namespaces.
Here, you can see, I have a namespace, GameEngine_CORE, where all the behind-the-scenes work is done. I have the namespace SandBox, which is where the user actually would write their game.
I need SandBox to be able to access some of the variables in GameEngine_CORE, which seems to work fine (I have put a list of using GameEngine_CORE::... to save the user's time).
However, I also need GameEngine_CORE to be able to call the start() and update() function in SandBox, but upon compilation I get an error every time I try and call something from SandBox, eg: SandBox::start();
'SandBox' is not a class or namespace name
I am coding in Visual Studio, and compiling in Debug mode for Windows x64.
#pragma once
#include "SDL.h"
#undef main
#include <iostream>
#include <math.h>
#include <vector>
#include <stdio.h> // Temp
#include "Vec2.h"
#include "Log.h"
#include "Time.h"
#include "Boundary.h"
#include "Ray.h"
#include "Particle.h"
#include "Polygon.h"
#include "Path.h"
#include "Circle.h"
namespace GameEngine_CORE {
// Renderer
SDL_Renderer* renderer;
SDL_Window* window;
bool isRunning;
bool fullscreen;
// Mouse
int mouseX;
int mouseY;
Uint32 mouse;
// Keyboard
Vec2 arrowInp;
// Collision Stack
std::vector<Boundary> collisionStack;
// Log
Log logger;
// Physics
Time timer;
Time clockTime;
float deltaTime;
Vec2 gravity = Vec2(0, -9.8f);
void handleEvents();
void render();
void createWindow();
void destroyWindow();
// For the SandBox Program
void SandBox::start();
void SandBox::update();
int main() { // Entry Point
double m_LastClock = 0.0;
clockTime.StartTimer(); // Start Counter
SandBox::start(); // For user
while (isRunning) {
double m_CurrentClock;
m_CurrentClock = clockTime.GetTimer(); // Get Counter
deltaTime = (float)(m_CurrentClock - m_LastClock);
if (deltaTime > 0.15f) {
deltaTime = 0.15f;
}
handleEvents();
render();
m_LastClock = m_CurrentClock;
}
destroyWindow();
return 0;
}
// Initialise the window to draw to
void createWindow() {
// Set window size and type
fullscreen = true;
Uint32 flags = 0;
flags = SDL_WINDOW_RESIZABLE;
if (fullscreen) {
flags = flags | SDL_WINDOW_MAXIMIZED;
}
if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
logger.Message("Subsystems Initialised");
window = SDL_CreateWindow("2D Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 300, 300, flags);
if (window) {
logger.Message("Window Created");
// Minimum window size
SDL_SetWindowMinimumSize(window, 1000, 1000);
}
// Create Renderer for window
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer) {
SDL_SetRenderDrawColor(renderer, 121, 121, 121, 255);
logger.Message("Renderer Created");
// Set how to blend alphas and colours
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
isRunning = true;
}
}
}
void destroyWindow() {
// Frees memory associated with renderer and window
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window); //error here
SDL_Quit();
}
// Handles SDL events
void handleEvents() {
// Check for quit
SDL_Event event;
SDL_PollEvent(&event);
// Check we have latest inputs
SDL_PumpEvents();
// Reset inputs
arrowInp.x = 0; arrowInp.y = 0;
// If we get quit event, stop running and free up memory
switch (event.type) {
case SDL_QUIT:
isRunning = false;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_LEFT: arrowInp.x = -1; break;
case SDLK_RIGHT: arrowInp.x = 1; break;
}
switch (event.key.keysym.sym)
{
case SDLK_UP: arrowInp.y = -1; break;
case SDLK_DOWN: arrowInp.y = 1; break;
}
break;
default:
break;
}
}
// Render Function
void render() {
// Set back ground colour and clear renderer every frame
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SandBox::update();
SDL_RenderPresent(renderer); // Draw to the screen
}
}
using GameEngine_CORE::createWindow;
using GameEngine_CORE::deltaTime;
using GameEngine_CORE::mouse;
using GameEngine_CORE::mouseX;
using GameEngine_CORE::mouseY;
using GameEngine_CORE::renderer;
using GameEngine_CORE::arrowInp;
using GameEngine_CORE::collisionStack;
namespace SandBox { // Where the user of the engine would write code
// Drawing Vars
Particle particle = Particle(50, 359.99f, Vec2(900, 700));
Boundary boundaries[] = { Boundary(Vec2(800, 0), Vec2(800, 1000)), Boundary(Vec2(300, 300), Vec2(400, 700)), Boundary(Vec2(300, 700), Vec2(800, 800)) };
GameEngine::Polygon square = GameEngine::Polygon(Vec2(800, 400), 45, Vec2(400, 200), 4);
GameEngine::Polygon poly1 = GameEngine::Polygon(Vec2(200, 400), Vec2(200, 200), 6);
GameEngine::Polygon ellipse = GameEngine::Polygon(Vec2(1200, 600), Vec2(200, 400), 64);
Path path = Path(Vec2(500, 100));
Circle circle = Circle(100, Vec2(800, 500));
GameEngine::Polygon player = GameEngine::Polygon(Vec2(700, 400), 0, Vec2(60, 60), 16);
float moveSpeed;
Vec2 velocity;
float rotator = 0;
// Functions
static void collision();
static void start() { // Called when the program starts
createWindow();
moveSpeed = 1000.0f;
path.addPoints(std::vector<Vec2> { Vec2(200, 100), Vec2(200, 800), Vec2(350, 800), Vec2(700, 650), Vec2(400, 400), Vec2(200, 100)});
}
static void update() { // Repeats every frame
printf("%f secs \n", deltaTime);
// Get the mouse' current state
mouse = SDL_GetMouseState(&mouseX, &mouseY);
particle.setPos(Vec2((float)mouseX, (float)mouseY));
SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); // Draw Boundaries
rotator += 0.01f;
poly1.setRot(rotator);
// Player
player.Show(renderer);
square.Show(renderer);
poly1.Show(renderer);
ellipse.Show(renderer);
path.Show(renderer);
collision();
}
static void collision() {
// Clears stack
collisionStack.clear();
// Adds colliders to stack
square.makeCollider(collisionStack);
poly1.makeCollider(collisionStack);
ellipse.makeCollider(collisionStack);
path.makeCollider(collisionStack);
player.makeCollider(collisionStack);
// Draw Particles
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 100);
particle.collide(renderer, collisionStack);
}
static void movement() {
Vec2 velocity = arrowInp * moveSpeed;
}
}
I don't imagine anyone needs to see the header files, but I can provide them if requested. I also declare my start() and update() functions in GameEngine_CORE, which I'm not sure is correct, however I was getting complaints from Visual Studio that it could not find the function definitions otherwise.

SFML - Weird RenderTexture behaviour when resizing window

I am currently trying to recreate Chess in SFML. Generating the board normally works as intended but when I am resizing the window I get weird white borders.
Before Resize:
After Resize:
It looks like the view is not aligned with the window properly so I think my problem is not in the board generation but how I am handling resizes. I thought manually updating the window view would help but it only ensured that the squares don't get streched. The border issue remains however so now I am quite clueless as to how I could fix this problem.
Board.h:
#pragma once
#include <SFML/Graphics.hpp>
class Board
{
public:
void createBoard(sf::Vector2u windowSize);
void drawBoard(sf::RenderWindow& window) const;
private:
sf::RenderTexture board;
sf::Color lightColor = sf::Color(159, 144, 176);
sf::Color darkColor = sf::Color(125, 74, 141);
sf::Color backColor = sf::Color(32, 31, 32);
};
Board.cpp:
#include <SFML/Graphics.hpp>
#include "Board.h"
void Board::createBoard(sf::Vector2u windowSize)
{
const float xOffset = static_cast<float>(windowSize.x - windowSize.y) / 2.f;
const float squareSize = static_cast<float>(windowSize.y) / 8.f;
board.create(windowSize.x, windowSize.y);
board.clear(backColor);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
sf::RectangleShape currSquare({ squareSize, squareSize });
currSquare.setFillColor((i + j) % 2 ? lightColor : darkColor);
currSquare.setPosition(xOffset + static_cast<float>(i) * squareSize, (static_cast<float>(j) * squareSize));
board.draw(currSquare);
}
}
}
void Board::drawBoard(sf::RenderWindow& window) const
{
window.draw(sf::Sprite(board.getTexture()));
}
main.cpp:
#include <SFML/Graphics.hpp>
#include "Board.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(500, 300), "Chess");
sf::Event event;
sf::View view = window.getDefaultView();
Board board;
board.createBoard(window.getSize());
while (window.isOpen()) {
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
else if (event.type == sf::Event::Resized) {
view.setSize({ static_cast<float>(event.size.width), static_cast<float>(event.size.height) });
window.setView(view);
board.createBoard({ event.size.width, event.size.height });
}
}
window.clear(sf::Color::White);
board.drawBoard(window);
window.display();
}
return 0;
}
Does anyone know how I could fix this problem?
The problem is that you don't only need to resize the view, but also recenter it. As right now you are not doing it, the center remains where the smaller board was and the bigger view takes a chunk from the outside in the top left corner.
So just change your code like this:
...
else if (event.type == sf::Event::Resized) {
float w = static_cast<float>(event.size.width);
float h = static_cast<float>(event.size.height);
view.setSize({w , h});
view.setCenter({w/2.f , h/2.f}); // <----- !
window.setView(view);
board.createBoard({ event.size.width, event.size.height });
}
...

OpenCV stop rendering while mouse moving

I have a simple window that contains simple black image with small solid circle inside it. I have wrote a simple code to be able to drag and drop this circle. I could do it correctly. Inside the mouse_event function:
void on_mouse_event(int event_type, int x, int y, int flags, void*){
if (event_type == cv::EVENT_RBUTTONDOWN){
//Catch the circle
}
else if (event_type == cv::EVENT_MOUSEMOVE){
//Release the point
}
else if (event_type == cv::EVENT_MOUSEMOVE){
//Change circle position according to curser moving
//re draw the circle again
//show the new image
}
}
The main function:
while (true){
//show image code (simple cv::imshow);
if (cv::waitKey(1) == 27){
break;
}
}
The problem is that if I drag the circle and start to move fast, the image will not change till I stop. However, if I go slowly it will change according to the move. What is the reason of this problem?
P.S I am not in doubt of slow hardware at all. I am working on workstation and I am mentoring the processor utilization and just one of its 8 core reach around 50% and the memory is almost free.
I am using Windows 10 if it helps.
you could test the following code.(adapted from opencv_annotation.cpp)
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
// Function prototypes
void on_mouse(int, int, int, int, void*);
// Public parameters
Mat image(600, 800, CV_8UC3, Scalar(220, 220, 220));
Mat current_view;
int circle_center_x = image.cols / 2, circle_center_y = image.rows / 2, radius = 40;
bool dragging = false;
const string window_name = "OpenCV Mouse Event Demo";
void on_mouse(int event, int x, int y, int, void *)
{
// Action when left button is clicked
if (event == EVENT_LBUTTONDOWN & (abs(circle_center_x - x) < 20) & (abs(circle_center_y - y) < 20))
{
dragging = true;
}
if (event == EVENT_LBUTTONUP)
{
dragging = false;
}
// Action when mouse is moving
if ((event == EVENT_MOUSEMOVE) && dragging)
{
image.copyTo(current_view);
circle_center_x = x;
circle_center_y = y;
circle(current_view, Point(circle_center_x, circle_center_y), radius, Scalar(255, 0, 0), 5);
imshow(window_name, current_view);
}
}
int main(int argc, const char** argv)
{
// Init window interface and couple mouse actions
namedWindow(window_name, WINDOW_AUTOSIZE);
setMouseCallback(window_name, on_mouse);
image.copyTo(current_view);
circle(current_view, Point(circle_center_x, circle_center_y), radius, Scalar(255, 0, 0), 5);
imshow(window_name, current_view);
int key_pressed = 0;
do
{
// Keys for processing
// Based on the universal ASCII code of the keystroke: http://www.asciitable.com/
// <SPACE> = 32 add circle to current image
// <ESC> = 27 exit program
key_pressed = 0xFF & waitKey(0);
if (key_pressed==32)
{
// draw a circle on the image
circle(image, Point(circle_center_x, circle_center_y), radius, Scalar(0, 0, 255), -1);
image.copyTo(current_view);
circle(current_view, Point(circle_center_x, circle_center_y), radius, Scalar(255, 0, 0), 5);
imshow(window_name, current_view);
}
}
// Continue as long as the <ESC> key has not been pressed
while (key_pressed != 27);
// Close down the window
destroyWindow(window_name);
return 0;
}

SFML Sprites not displaying at all

I have a method which should take a spritesheet which is 64x128 and turn it into 8x8 sprites.
after each texture is found from the stored Image, it is added to a sprite, and that sprite is added to a sprite array which is being called in my main method.
I have tested displaying a static sprite before, and my code worked (I displayed 1 8x8 sprite successfully)
However, when trying to display any of the 128 sprites in my list of sprites, now none are being rendered.
I believe the logic error may be in my MakeSprite method, but I'm unsure, and I can't see where the issue is.
[EDIT]: it seems that every sprite I call is returning the sprite at the very end of the spritesheet (sprite 128)
[Edit 2]: the texture (tex) of the previous sprite is overwritten by the next sprite to be spawned.
Below is a full verifiable working example of my code:
main.cpp
#include "Main.h"
int main() {
srand(time(NULL));
RenderWindow window(VideoMode(1280, 720), "Conduit");
MakeCircle(10, 100, 100, Color::White);
MakeCircle(30, 10, 100, Color::Cyan);
MakeCircle(100, 200, 100, Color::Magenta);
MakeCircle(100, 400, 100, Color::Cyan);
if (!LoadSpritesheet())
{
return 1;
}
while (window.isOpen()) {
Event event;
while (window.pollEvent(event)) {
if (event.type == Event::Closed)
window.close();
else if (event.key.code == Keyboard::Num1)
{
DrawRandomSprite(window);
}
}
window.clear();
DrawCircles(window);
int c = 0;
for (int i = 0; i < 128; i++)
{
Spritesheet.at(i).setPosition(c, c);
window.draw(Spritesheet.at(i));
c += 8;
}
window.display();
}
}
void DrawRandomSprite(RenderWindow &window)
{
//DEBUG METHOD: draws a random sprite for testing.
int sprite = rand() % 128 + 1;
Spritesheet.at(sprite).setPosition(rand() % 128 + 1, rand() % 128 + 1);
window.draw(Spritesheet.at(sprite));
}
void MakeCircle(float radius, float xpos, float ypos, Color color)
{
//makes a circle then adds it to the circle vector.
CircleShape shape;
shape.setRadius(radius);
shape.setPosition(xpos, ypos);
shape.setFillColor(color);
Circles.push_back(shape);
}
void DrawCircles(RenderWindow &window)
{
//Renders the circles in the circles vector.
for (int i = 0; i < Circles.size(); i++)
{
window.draw(Circles.at(i));
}
}
int LoadSpritesheet()
{
//make sure spritesheet exists, then loads it into an image.
Texture sheet;
if (!sheet.loadFromFile("Sprites/A.png"))
{
return 0;
}
else
{
sheetIMG = sheet.copyToImage();
SetMask();
MakeSprite(8, 4);
return 1;
}
}
void SetMask()
{
//creates a mask.
sheetIMG.createMaskFromColor(sf::Color(151, 56, 14, 0), 100);
}
void MakeSprite(int dimension, int scale)
{
//seperates the spritesheet into a list of 8x8 modular sprites.
int c = 0, r = 0;
do
{
for (int i = 0; i <= (sheetIMG.getSize().x * sheetIMG.getSize().y) / 64; i++)
{
if (r == 64)
break;
if (!tex.loadFromImage(sheetIMG, IntRect(c, r, dimension, dimension)))
break;
else
{
Sprite spr;
spr.setTexture(tex);
spr.setScale(scale, scale);
Spritesheet.push_back(spr);
c += dimension;
if (c == sheetIMG.getSize().x) { c = 0; r+=8; };
}
}
} while (r < sheetIMG.getSize().y);
}
Main.h
#pragma once
#include <SFML/Graphics.hpp>
#include <vector>
#include <stdio.h> /* printf, scanf, puts, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
//standard and SFML namespaces;
using namespace std;
using namespace sf;
//===============================VARIBLES===========================
//the main spritesheet.
Texture tex;
Image sheetIMG;
//array to hold circles.
vector<CircleShape> Circles;
//array to hold sprites.
vector<Sprite> Spritesheet;
//===============================PROTOTYPES=============================
void DrawCircles(RenderWindow &window);
void MakeCircle(float radius, float xpos, float ypos, Color color);
void MakeSprite(int dimension, int scale);
void SetMask();
int LoadSpritesheet();
void DrawRandomSprite(RenderWindow &window);
There's two major issues with your code:
You're using global variables. While this might be okay with some libraries, with SFML this is not a good thing at all.
You're clearing the window after calling DrawRandomSprite. Therefore your sprite will never show up.
All your sprites have the same texture: tex. And as tex is a single global variable, when your loop finishes, it's set to the last texture. So all sprites will draw the last texture. You need to get rid of the globals and have one texture per sprite (or at least one per sprite that you want to have a different texture).