breakout collision detection using vectors - c++

I am working on a breakout game using C++ and OpenGL. I have stubbed out some code using straight C++. I am using a vector to store objects.
I want to streamline my collision detection code.I am working on breakout game using vectors to store brick values in text based c++ to start with. Well I am attempting to use a vector as a dynamic array. Basically I want to store the values of the bricks in a vector. I then want to iterate through the vector in order to determine if a brick is hit by the ball. I am able to detect if a single brick is hit by the ball but I want to determine if a vector of brick values are hit by a ball. In other words instead of using a collision detection loop for each and every single brick one at a time but I want the vector to store the values for the bricks so that I can iterate through them dynamically.
My code:
class Brick
{
public:
float x;
float y;
float brick_x;
float brick_y;
float brickWidth;
float brickHeight;
};
int main()
{
vector<Brick> brick;
Brick playerBrick;
Brick playerBrick_two;
playerBrick.x = 30.0f;
playerBrick.y = 20.0f;
playerBrick.brick_x = 20.0f;
playerBrick.brick_y = 10.0f;
playerBrick.brickWidth = 60.0f;
playerBrick.brickHeight = 20.0f;
playerBrick_two.x = 40.0f;
playerBrick_two.y = 30.0f;
playerBrick_two.brick_x = 30.0f;
playerBrick_two.brick_y = 20.0f;
playerBrick_two.brickWidth = 60.0f;
playerBrick_two.brickHeight = 20.0f;
brick.push_back(playerBrick);
brick.push_back(playerBrick_two);
for (int i = 0; i < 2; i++)
{
cout << brick[i].x << " " << brick[i].y << " " << brick[i].brick_x << " " << brick[i].brick_y << " " << brick[i].brickWidth << " " << brick[i].brickHeight << endl;
}
for (int i = 0; i < 2; i++)
{
if (brick[i].x > brick[i].brick_x && brick[i].x < brick[i].brick_x + brick[i].brickWidth && brick[i].y > brick[i].brick_y && brick[i].y < brick[i].brick_y + brick[i].brickHeight)
{
cout << "Collision" << endl;
}
}
void bricks_eight()
{
glColor3f(0.8f, 0.0f, 0.0f);
glRectf(50.0f, 60.0f, 70.0f, 50.0f);
glRectf(70.0f, 60.0f, 90.0f, 50.0f);
glRectf(90.0f, 60.0f, 110.0f, 50.0f);
glRectf(110.0f, 60.0f, 130.0f, 50.0f);
glRectf(130.0f, 60.0f, 150.0f, 50.0f);
glRectf(150.0f, 60.0f, 170.0f, 50.0f);
}
Well I am posting a row of bricks I want to eliminate when the ball strikes with them. Since I have several rows of bricks I want to use a collision detection function that checks for a ball and brick collision using a vector. The x and y variables are the ball coordinates and the brick_x and brick_y variables and the brick coordinates.
I adjusted Makogan's code but it still does not check for a lot collisions all at once.
``
class Brick
{
public:
float x;
float y;
float brick_x=0.0f;
float brick_y=0.0f;
float brickWidth=20.0f;
float brickHeight=10.0f;
bool TestCollision(float x, float y)
{
if (x > brick_x && x<brick_x + brickWidth && y > brick_y && y < brick_y + brickHeight)
{
return true;
}
return false;
}
};
class BrickLayer
{
public:
vector<Brick> bricks{(5.0f,5.0f)};
bool TestCollisions(float x, float y) {
for (auto& brick : bricks) if (brick.TestCollision(x, y)) return true;
return false;
}
};
int main()
{
BrickLayer brick;
cout << brick.TestCollisions(5.0f,5.0f)<< endl;
system("pause");
return 0;
}

Based on the comments, it sounds like you just need a wrapper to abstract detecting collisions for a group / row of your bricks.
So my suggestion is
class Brick
{
public:
float x;
float y;
float brick_x;
float brick_y;
float brickWidth;
float brickHeight;
TestCollision(float x,float y) {/* check goes here */}
};
class BrickLayer
{
public:
vector<Brick> bricks;
float min_x;
float min_y;
float total_width;
float total_height;
BrickLayer(vector<Brick> bricks) {/* initialize the instance fields here */}
// Option 1, iterating over every brick:
bool TestCollisions(float x, float y) {
for(auto& brick : bricks) if(brick.testCollision(x,y)) return true;
return false;
}
// Option 2, use cached information:
bool TestCollisions(float x, float y) {
if (x > min_x && x < min_x + total_width && y > min_y && y < min_y + total_height)
return true;
}
};

Related

Function will not modify Struct objects that are passed as pointers(or references)

Edit: Code is now runnable
So I am trying to update the position of objects in a struct and I have tested the code within the Update and Rule function both execute and the local variables in the Rule class change as expected. What doesn't change are the member variables of the struct objects of type Object.
Here is the relevant code in my cpp file:
struct Object
{
float x;
float y;
float vx;
float vy;
glm::vec4 v_Color;
unsigned int id;
Object(float _x, float _y,
float _vx, float _vy,
glm::vec4 _v_Color, unsigned int _id)
{
x = _x;
y = _y;
vx = _vx;
vy = _vy;
v_Color = _v_Color;
id = _id;
}
}
std::vector<Object> red;
std::vector<Object> green;
std::vector<Object> blue;
std::vector<Object> yellow;
void Rule(std::vector<Object>* group1, std::vector<Object>* group2, float G)
{
float g = G;
for (int i = 0; i < group1->size(); i++) {
Object p1 = (*group1)[i];
float fx = 0;
float fy = 0;
for (int j = 0; j < group2->size(); j++) {
Object p2 = (*group2)[j];
float dx = p1.position.x - p2.position.x;
float dy = p1.position.y - p2.position.y;
float r = std::sqrt(dx * dx + dy * dy);
if (r < 80 && r > 0) {
fx += (dx / r);
fy += (dy / r);
}
}
p1.velocity.x = (p1.velocity.x + fx) * 0.5;
p1.velocity.y = (p1.velocity.y + fx) * 0.5;
p1.position.x += p1.velocity.x;
p1.position.y += p1.velocity.y;
if ((p1.position.x >= 800) || (p1.position.x <= 0)) { p1.velocity.x *= -1; }
if ((p1.position.y >= 700) || (p1.position.y <= 0)) { p1.velocity.y *= -1; }
std::cout << "Calculated velocity: " << fx << ", " << fy << std::endl; // these numbers will change
(*group1)[i] = p1;
std::cout << "ID: " << p1.id << ", " << "Velocity " << p1.velocity.x << ", " << p1.velocity.y << "Position: " << p1.position.x << ", " << p1.position.y << std::endl; // you will see these values do not change
}
}
std::vector<Object> CreateObjects(unsigned int number, glm::vec4 color)
{
std::vector<Object> group;
for (int i = 0; i < 10; i++) {
float x = rand() % 750 + 50;
float y = rand() % 550 + 50;
Object o(x, y, 0, 0, color, objects.size());
group.push_back(o);
objects.push_back(o);
}
return group;
}
void main()
{
yellow = CreateObjects(10, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
blue = CreateObjects(10, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
green = CreateObjects(10, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
red = CreateObjects(10, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
Rule(&green, &green, -0.32);
Rule(&green, &red, -0.17);
Rule(&green, &yellow, 0.34);
Rule(&red, &red, -0.1);
Rule(&red, &green, -0.34);
Rule(&yellow, &yellow, 0.15);
Rule(&yellow, &green, -0.2);
Rule(&blue, &green, -0.2);
}
Edit: Code should now be runnable
You should debug your program to see in which exact step the program behaves as not expected
pointer to std::vector actually modifies your object.
you should see it if you add another field - int counter in your Object struct
struct Object
{
glm::vec3 position;
glm::vec3 velocity;
glm::vec4 v_Color;
unsigned int id;
int counter; // dont forget to initialise it in Object constructor
and here
void Rule(std::vector<Object>* group1, std::vector<Object>* group2, float G)
simply add
p1.counter += 1;
Either you actually modify values but presicion is small to notice it. Or there is some kind of mistake on your side. May be glm::vec3 fields x and y should be modified another way than glm::vec3::x += val
P.S
some sources from the internet says that you can access vec3 cooridates but cant change them. Seems like your case
https://www.reddit.com/r/cpp_questions/comments/60nsl5/accessing_the_x_y_and_z_values_of_a_vec3_position/

Class inheritance with vector of parents having plural child elements

I'm trying to build a gamengine, and I need to sort characters and rooftiles based on the y-coordinate of their feet before drawing them, so that folk/tiles infront are drawn ontop of folk/tiles behind them. I've gotten it to work with just characters, but I need rooftiles as well.
the classes are both children of renderable, and share some data. The classes are forward-declared, and there are global lists g_entities, g_tiles, and g_renderable.
class renderable {
public:
float x;
float y;
float width;
float height;
SDL_Surface* image;
SDL_Texture* texture;
void render(SDL_Renderer * renderer, camera fcamera) {
rect obj(floor((x -fcamera.x)* fcamera.zoom), floor((y-fcamera.y)* fcamera.zoom), floor(width *fcamera.zoom), floor(height * fcamera.zoom));
rect cam(0, 0, fcamera.width, fcamera.height);
if(RectOverlap(obj, cam)) {
SDL_Rect dstrect = { (x -fcamera.x)* fcamera.zoom, (y-fcamera.y)* fcamera.zoom, width *fcamera.zoom, height * fcamera.zoom};
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
}
}
};
class entity: public renderable {
public:
float x;
float y;
float xagil;
float yagil;
//... other stuff, including image and texture
void render(SDL_Renderer * renderer, camera fcamera);
};
class tile: public renderable {
public:
int x;
int y;
int z = 0; //represents layer. 0 default
float width;
float height;
//... other stuff, including image and texture
void render(SDL_Renderer * renderer, camera fcamera);
};
The list is created when the map is loaded with
for (int i = 0; i < g_entities.size(); i++) {
g_renderable.push_back(g_entities[i]);
}
for (int i = 0; i < g_tiles.size(); i++) {
if(g_tiles[i]->z ==2) {
g_renderable.push_back(g_tiles[i]);
g_tiles.erase(g_tiles.begin() + i);
i--;
}
}
And then in main I planned to sort the g_renderable array instead of the g_entities array and have everything snug, but instead I get a SIGFAULT. I tracked down the problem with GDB and it turns out that g_renderable[] isnt getting informed with the attributes of g_entities[] (and probly not g_tiles[] either).
This is what I mean:
g_renderable.clear();
g_renderable.reserve(g_entities.size() + g_tiles.size()); // preallocate memory
cout << "g_entities.size" <<g_entities.size() << endl;
cout << "g_entities.size" <<g_entities.size() << endl;
cout << "g_entities height " << g_entities[0]->height << endl; //couts 122
for (int i = 0; i < g_entities.size(); i++) {
g_renderable.push_back(g_entities[i]);
}
cout << "g_renderable height " << g_renderable[0]->height << endl; //couts 0
for (int i = 0; i < g_tiles.size(); i++) {
if(g_tiles[i]->z ==2) {
g_renderable.push_back(g_tiles[i]);
g_tiles.erase(g_tiles.begin() + i);
i--;
}
}
Why doesnt my vector return the member data as expected?

How to fix vertical artifact lines in a vertex array in SFML, WITH pixel perfect zoom/move?

I have been working on a 2D top-down game solely in SFML and C++, that has a tilemap. I cannot rid the tilemap of vertical line artifacts when zooming in and out or moving the render view at different zoom levels. I attached an image below of the problem; circled in red.
[edit]
There are a lot of factors that make this bug inconsistent.
If I use a tile_atlas from only one tile, there is no artifacts. If I map each texture to a tile a.k.a not using vertex arrays; I did not see any artifacts but it is anywhere from 10x to 15x slower with the same number of tiles on the screen. I have tried finding zoom levels that don't cause artifacts, and there are some. but the levels are almost random and makes zoom in and out, not smooth and choppy.
I have tried numerous tutorials and forum "fixes" that have not completely worked. I have completely rewrote the underlying tile engine 4 separate times to no avail.
https://en.sfml-dev.org/forums/index.php?topic=15747.0
topic=14504
topic=5952
topic=13637.15
https://www.sfml-dev.org/tutorials/2.5/graphics-view.php
https://www.binpress.com/creating-city-building-game-with-sfml/
https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php
[edit]
I have read the Terreria scaling issue, the fix to make extra large textures then scale, or multiple textures, one for each zoom level. seem exhaustive. I am looking for a programmatic way of achieving the scaling correctly.
This is post is my last attempt to fix the code, otherwise I will need to change languages.
I believe the main issue comes from the zoom in/out functions of the program.
I have tried many, variations/attempt to get this to work +0.5f offset,+0.375f offset, not pixel perfect
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;
float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
Here is the entire code.
main.cpp
#include "chunk_map.h"
#include "tile_atlas.h"
#include <vector>
//#include "main.h"
#include "map.h"
#include <iostream>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/View.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>
#include "animation_handler.h"
int main(int argc, char* argv[])
{
sf::RenderWindow app(sf::VideoMode(600, 600), "Tilemap Example");
// Hard set fps to monitor refresh rate.
// textures to load.
/*text_mgr.loadTexture("grass", "grass.png");
text_mgr.loadTexture("high_grass", "high_grass.png");
Animation staticAnim(0, 0, 1.0f);
tileAtlas["grass"] = Tile(32, 1, text_mgr.getRef("grass"),{ staticAnim },
TileType::GRASS, 50, 0, 1);
tileAtlas["high_grass"] = Tile(32, 1, text_mgr.getRef("high_grass"),{ staticAnim },
TileType::HIGH_GRASS, 100, 0, 1);*/
//Map map;
//map.load(50, 50, tileAtlas);
#ifdef NDEBUG
app.setVerticalSyncEnabled(true);
std::cout << "#################\n";
#endif // DEBUG
//app.setVerticalSyncEnabled(true);
sf::View cam = app.getDefaultView();
tile_atlas atlas = tile_atlas();
std::vector<chunk_map> map;
for (int x = 0; x < 5; x++)
{
for (int y = 0; y < 5; y++)
{
map.push_back(chunk_map());
map.back().set_texture(atlas.get_atlas());
map.back().set_position(10 * x, 10 * y, 10 * (x + 1), 10 * (y + 1));
map.back().load_tiles();
}
}
sf::Clock clock;
int checked = 0;
int last_sq = 600;
while (app.isOpen())
{
//sf::Time elapsed = clock.restart();
//float dt = elapsed.asSeconds();
sf::Event eve;
while (app.pollEvent(eve))
if (eve.type == sf::Event::Closed)
app.close();
if (sf::Keyboard::isKeyPressed(sf::Keyboard::P))
std::cout << "view x: " << cam.getSize().x << "\tview y: " << cam.getSize().y << std::endl;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
{
float zoom_out = 1.005f;
float nz = last_sq * zoom_out;
nz = std::ceil(nz);
float now = nz / last_sq;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
float zoom_in = 0.995f;
float nz = last_sq * zoom_in;
nz = std::floor(nz);
float now = nz / last_sq;
if (nz <= 10)
continue;
last_sq = nz;
std::cout << now << std::endl;
cam.zoom(now);
//float x = cam.getCenter().x;
//float y = cam.getCenter().y;
//x = std::floor(x);
//y = std::floor(y);
////std::cout << "x: " << x << "\ty: " << y << std::endl;
//cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
cam.move(0.f, -0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
cam.move(-0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::floor(x);
y = std::floor(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
cam.move(0.f, 0.02f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
cam.move(0.02f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
//std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
sf::Time elapsed = clock.getElapsedTime();
float t = elapsed.asSeconds();
int time = std::floor(t);
if (checked < time)
{
checked = time;
cam.move(0.01f, 0.f);
float x = cam.getCenter().x;
float y = cam.getCenter().y;
x = std::ceil(x);
y = std::ceil(y);
std::cout << "x: " << x << "\ty: " << y << std::endl;
cam.setCenter(x, y);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
app.close();
app.setView(cam);
#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);
for (int i = 0; i < 25; i++)
{
app.draw(map.at(i));
}
app.display();
}
}
chunk_map.h
#pragma once
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <vector>
class chunk_map : public sf::Drawable
{
private:
//change values of these to match your needs and improve performance
enum { tilesize = 32, chunksize = 32};
//tile size float
float tile_size_float = 32.0f;
// Draw chunk
virtual void draw(sf::RenderTarget& target, sf::RenderStates states)const;
// texture for chunk
sf::Texture m_texture;
// chunk dimensions
int tiles_per_chunk_x;
int tiles_per_chunk_y;
//start x and y and ending x and y scaled to tile size. a.k.a.
// 1,1 = tile 1,1. 10,10, equals tile 10,10
int chunk_start_x;
int chunk_start_y;
int chunk_end_x;
int chunk_end_y;
// Vertex array of positions of tiles in chunk
std::vector<std::vector<sf::VertexArray> > m_chunks;
// Append tiles.
void append_tile(int gx, int gy, sf::VertexArray& garr);
public:
chunk_map();
~chunk_map();
void load_tiles();
void set_texture(sf::Texture);
void set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y);
};
chunk_map.cpp
#include "chunk_map.h"
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Vertex.hpp>
chunk_map::chunk_map()
{
}
chunk_map::~chunk_map()
{
}
void chunk_map::load_tiles()
{
/*
Tile loading this is were the tiles are added to the Quadrantics of the tilemap.
this is the entire chunk_map loop
*/
if ((chunk_end_x * chunk_end_y) == 0)//empty map - possibly forgotten to fill data struct
{
//to stop displaying at all after failed loading:
tiles_per_chunk_x = 0;
tiles_per_chunk_y = 0;
m_chunks.clear();
return;
}
chunk_map::tiles_per_chunk_x = (chunk_end_x / chunksize) + 1;
chunk_map::tiles_per_chunk_y = (chunk_end_y / chunksize) + 1;
m_chunks.assign(tiles_per_chunk_x, std::vector<sf::VertexArray>(tiles_per_chunk_y, sf::VertexArray(sf::Quads)));//ready up empty 2d arrays
for (int iy = chunk_start_y; iy < chunk_end_y; ++iy)
{
for (int ix = chunk_start_x; ix < chunk_end_x; ++ix)
{
append_tile(ix, iy, m_chunks[ix / chunksize][iy / chunksize]);
}
}
}
void chunk_map::append_tile(int gx, int gy, sf::VertexArray& garr)
{
/*
This is the specific tile vertex, broken from the other function to decrease complexitity.
*/
int tile_selection_index_x = rand() % 2;
int tile_selection_index_y = 0;
float f_tx = tile_selection_index_x * tile_size_float;
float f_ty = tile_selection_index_y * tile_size_float;
sf::Vertex ver;
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top left corner
//ver.texCoords = sf::Vector2f( 0.f, 0.f);
ver.texCoords = sf::Vector2f(f_tx, f_ty);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float);
//texture in position of text atlas
//top right corner
//ver.texCoords = sf::Vector2f( tile_size_float, 0.f);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float + tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom right corner
//ver.texCoords = sf::Vector2f( tile_size_float, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx + tile_size_float, f_ty + tile_size_float);
garr.append(ver);
//____________________________________________________________________________________________________________
ver.position = sf::Vector2f(gx * tile_size_float, gy * tile_size_float + tile_size_float);
//texture in position of text atlas
//bottom left corner
//ver.texCoords = sf::Vector2f( 0.f, tile_size_float);
ver.texCoords = sf::Vector2f(f_tx, f_ty + tile_size_float);
garr.append(ver);
}
void chunk_map::set_texture(sf::Texture t)
{
/*
Sets the texture data for this chunk map from the texture atlas.
*/
m_texture = t;
// TODO test this feature
// Attempt to optimize tearing on zooming to a different view.
//m_texture.setSmooth(true);
}
void chunk_map::set_position(int chunk_start_x, int chunk_start_y,
int chunk_end_x, int chunk_end_y)
{
/*
Initialize the accordinates of the start of the chunk_map to the end.
*/
chunk_map::chunk_start_x = chunk_start_x;
chunk_map::chunk_start_y = chunk_start_y;
chunk_map::chunk_end_x = chunk_end_x;
chunk_map::chunk_end_y = chunk_end_y;
}
void chunk_map::draw(sf::RenderTarget& target, sf::RenderStates states)const
{
/*
The actual draw call to this specific chunk_map
*/
// position variables for this draw.
int left = 0;
int right = 0;
int top = 0;
int bottom = 0;
//get top left point of view
sf::Vector2f temp = target.getView().getCenter() - (target.getView().getSize() / 2.f);
//get top left point of view
left = static_cast<int>(temp.x / (chunksize * tilesize));
top = static_cast<int>(temp.y / (chunksize * tilesize));
//get bottom right point of view
temp += target.getView().getSize();
right = 1 + static_cast<int>(temp.x / (chunksize * tilesize));
bottom = 1 + static_cast<int>(temp.y / (chunksize * tilesize));
//clamp these to fit into array bounds:
left = std::max(0, std::min(left, tiles_per_chunk_x));
top = std::max(0, std::min(top, tiles_per_chunk_y));
right = std::max(0, std::min(right, tiles_per_chunk_x));
bottom = std::max(0, std::min(bottom, tiles_per_chunk_y));
//set texture and draw visible chunks:
states.texture = &m_texture;
for (int ix = left; ix < right; ++ix)
{
for (int iy = top; iy < bottom; ++iy)
{
target.draw(m_chunks[ix][iy], states);
}
}
}
tile_atlas.h
#pragma once
#include <SFML/Graphics/Texture.hpp>
class tile_atlas
{
private:
sf::Texture atlas_texture;
public:
tile_atlas();
~tile_atlas();
sf::Texture& get_atlas();
};
tile_atlas.cpp
#include "tile_atlas.h"
#include <iostream>
#include <string>
tile_atlas::tile_atlas()
{
std::string file_string = "tilemap_test.png";
if (!atlas_texture.loadFromFile(file_string))
{
std::cout << "Failed loading file: " << file_string << std::endl;
exit(1);
}
}
tile_atlas::~tile_atlas()
{
}
sf::Texture& tile_atlas::get_atlas()
{
return atlas_texture;
}
I am trying to fix this code to remove vertical artifacts so the above image will always look like this no matter if moving the view or zooming in/out.
[code for answer]
Using #Mario's answer this is the code I wrote (at the bottom of main.cpp) that completely fixed the artifacts.
here is a great link showing an example.
https://www.sfml-dev.org/tutorials/2.5/graphics-draw.php#off-screen-drawing
#ifdef _DEBUG
app.clear();
#endif // DEBUG
//map.draw(app, dt);
/*-----------------------------------------------------------*/
// Draw the texture
//rt.clear();
rt.draw(map.at(0));
rt.display();
if (cam.getSize().x < 500)
{
rt.setSmooth(false);
}
else
{
rt.setSmooth(true);
}
//// get the target texture (where the stuff has been drawn)
const sf::Texture& texture = rt.getTexture();
sf::Sprite sprite(texture);
app.draw(sprite);
//app.draw(map.at(0));
/*-----------------------------------------------------------*/
app.display();
Simple, yet effective:
Render your pixels 1:1 without scaling to a render texture and then upscale that instead.
Might be a bit tricky to determine the correct position, zoom, etc. but it can be done.

Removing an object from a vector by index

I have a for loop that looks like this:
for (int i = Particles.size() - 1; i >= 0; i--) {
if (Particles[i].Dead) {
Particles.erase(Particles.begin() + i);
}
}
When I compile, I get this error:
Error C2280 'Particle &Particle::operator =(const Particle &)': attempting to reference a deleted function
Gravity C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility 2518
Anyone know what I'm doing wrong? Here's the particle code.
Header file
class Particle
{
public:
const float G = 6.674 * pow(10, -11);
float Mass, Radius;
Vector2 Position, Velocity, Force;
bool Dead = false;
void Gravity(Particle Particle2);
void Move();
void Draw(SDL_Surface *Surface, Uint32 Color);
Particle(float MassBounds[2], Vector2 PositionBounds[2], float Density);
Particle::Particle(float Mass, Vector2 Position, float Density, bool NonRandom);
Particle();
};
Source file
void Particle::Gravity(Particle Particle2)
{
float GravityMagnitude = (Particle::G*Mass*Particle2.Mass) / Vector2::DistanceSquared(Position, Particle2.Position);
Force += (Particle2.Position - Position).Normalised()*GravityMagnitude;
}
void Particle::Move()
{
Velocity += Force/Mass;
Position += Velocity;
}
void Particle::Draw(SDL_Surface *Surface, Uint32 Color)
{
if (int(Radius) > 0) { SDLDrawFilledCircle(Surface, int(Position.x), int(Position.y), Radius<1?1:int(Radius), Color); }
}
Particle::Particle(float MassBounds[2], Vector2 PositionBounds[2], float Density)
{
Mass = RandRange(MassBounds);
Position = Vector2(RandRange(PositionBounds[0].x, PositionBounds[1].x), RandRange(PositionBounds[0].y, PositionBounds[1].y));
Radius = pow((3.0 * Mass) / (4 * M_PI*Density), 1.0 / 3.0);
Velocity = Vector2();
Force = Vector2();
}
Particle::Particle(float Mass, Vector2 Position, float Density, bool NonRandom)
{
this->Mass = Mass;
this->Position = Position;
Radius = pow((3.0 * Mass) / (4 * M_PI*Density), 1.0 / 3.0);
Velocity = Vector2();
Force = Vector2();
}
Particle::Particle()
{
Mass = 1;
Position = Vector2();
Radius = 1;
Velocity = Vector2();
Force = Vector2();
}
inline bool operator==(const Particle& a, const Particle& b) { return a == b; }
You may have better luck using remove_if and erase:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct Vector {
int x;
int y;
};
bool is_negative (Vector a) {
return a.x < 0 && a.y < 0;
}
int main() {
vector<Vector> vectors;
vectors.push_back({-1, -2});
vectors.push_back({-1, 2});
vectors.push_back({1, 2});
vectors.push_back({-1, -2});
vectors.erase(
std::remove_if(vectors.begin(), vectors.end(), is_negative),
vectors.end());
for (auto v : vectors) {
cout << v.x << " " << v.y << endl;
}
}
I could not help notice this in your for loop:
Particles.erase(Particles.begin() + i-1)
More importantly
i - 1
You start with
i = Particles.size() - 1
and do not stop until
i < 0
This
Particles.begin()
gives you the head of the list.
When
i == 0
Particles.begin() + (i - 1)
will try to get invalid node.
Which translates to
Particles.begin() - 1
I do not know when your code breaks, I am going based on your loop
Here is link w/doc http://www.cplusplus.com/reference/vector/vector/erase/
Hope this helps

OpenGL 2D Hex Board shaped like a Rhombus

So I am working on a GUI for a Hex Board game. Hex game has 121 Hex Shapes in an 11 by 11 Rhombus. I have drawn an 11 by 11 board that is shaped like a Quad or a square. How would I go about translating the coordinates to draw the Hex shapes like a rhombus? Here is the piece of my code that draws the board every frame.
void draw_Board(HexBoard* h) {
glPushMatrix();
glTranslatef(1.5f, 1.5f, 0.0f);
for (auto iter = h->drawList.begin(); iter != h->drawList.end(); ++iter) {
pointRef t = *iter;
colorRef c;
float scale_factor = h->get_scale_factor();
if (t.player == 0) {
c.red = 1;
c.green = 1;
c.blue = 1;
}
else if (t.player == 1) {
c.red = 1;
c.green = 0;
c.blue = 0;
}
else if (t.player == 2) {
c.red = 0;
c.green = 0;
c.blue = 1;
}
int x_increment = 2;
int y_increment = 2;
glPushMatrix();
//cout << t.x_pos << " " << t.y_pos << endl;
//cout << c.red << " " << c.green << " " << c.blue << endl;
glTranslatef(t.x_pos * 2 , t.y_pos * 2, 0);
draw_Hex(c, scale_factor);
glPopMatrix();
}
glPopMatrix();
}
Here is how my board looks like
http://imgur.com/criFeDM
Goal shape is this
http://upload.wikimedia.org/wikipedia/commons/3/38/Hex-board-11x11-%282%29.jpg
You need to grasp the basic trigonometry behind hexagons
as you can see there are two valid angles 30 and 60 degrees. I assume you have no problem of obtaining the hexagon points itself so focus on the i,j step in the grid then:
i-step is 2*dx which is 2.0*r*cos(30deg) in x-axis
j-step changes booth x and y and it is
dx in x-axis and 2.0*dx*sin(60deg) in y-axis
now just create loop through your grid and compute each hexagon start point ...
This is the result for 10x10 grid:
Here the source in C++:
//---------------------------------------------------------------------------
#include <math.h>
const float hexagon_r=0.2;
const float hexagon_dx=hexagon_r*cos(30.0*M_PI/180.0);
const float hexagon_dy=hexagon_r*sin(30.0*M_PI/180.0);
const float hexagon_gx=2.0*hexagon_dx;
const float hexagon_gy=2.0*hexagon_dx*sin(60.0*M_PI/180.0);
void draw_hexagon(float x,float y,float z)
{
glBegin(GL_LINE_LOOP);
glVertex3f(x-hexagon_dx,y-hexagon_dy,z);
glVertex3f(x-hexagon_dx,y+hexagon_dy,z);
glVertex3f(x ,y+hexagon_r ,z);
glVertex3f(x+hexagon_dx,y+hexagon_dy,z);
glVertex3f(x+hexagon_dx,y-hexagon_dy,z);
glVertex3f(x ,y-hexagon_r ,z);
glEnd();
}
//---------------------------------------------------------------------------
void draw_hexagon_grid(float x,float y,float z,int ni,int nj)
{
int i,j; float x0;
x-=float(ni-1)*hexagon_gx*0.5; // just shift x,y to start position (i=0,j=0)
x-=float(nj-1)*hexagon_dx*0.5;
y-=float(nj-1)*hexagon_gy*0.5;
for (x0=x,j=0;j<nj;j++,x0+=hexagon_dx,x=x0,y+=hexagon_gy)
for (i=0;i<ni;i++,x+=hexagon_gx)
draw_hexagon(x,y,z);
}
//---------------------------------------------------------------------------
Usage is simple: draw_hexagon_grid(0.0,0.0,-7.0,10,10);
x,y,z is the center point of grid (I have 3D view therefore I got z=-7 just to get the grid before camera)
ni,nj is the grid size in x and y axis
you can ignore the z axis ...