I'm currently learning SFML on my own, and trying to figure out how to print out the position of the clicked area at bposX and bposY in the pollevent section. Thi s is my codes:
sf::RectangleShape smallRectangle (float width = 1.0f, float height = 1.0f,
sf::Vector2f position = sf::Vector2f(1.0f,1.0f),
const sf::Color& myFillColor = sf::Color(0,51, 51)
)
{
sf::RectangleShape sboard;
sf::Vector2f myRectangleSize(width, height);
sboard.setSize(myRectangleSize);
sboard.setPosition(position);
sboard.setFillColor(myFillColor);
return sboard;
}
case sf::Event::MouseButtonPressed:
switch(event.mouseButton.button)
case sf::Mouse::Left:
{
float bposX = sboard.getPosition().x;
float bposY = sboard.getPosition().y;
cout << "Current Position : ";
cout << bposX << " " << bposY << endl;
break;
}
for(int i=0; i < sgridSize; i++)
{
for (int j = 0; j < sgridSize; j++)
{
window.draw(sgrid[i][j]);
sf::FloatRect sgridBounds = sgrid[i][j].getGlobalBounds();
if(sgridBounds.contains((sf::Vector2f)pointerPos))
{
shighlightCell.setPosition(sgrid[i][j].getPosition());
window.draw(shighlightCell);
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sgrid[i][j].setFillColor(sf::Color::Green);
}
}
}
}
When I click in rectangle it only displays 1 1, based on my Vector2f position.
Assuming I'm reading your code properly, sboard is a sf::RectangleShape. Chances are you actually want the position of the mouse, not this rectangle. Mouse position is given through the static function sf::Mouse::getPosition() which gives coordinates relative to desktop or sf::Mouse::getPosition(window) which will give you the position of the mouse relative to a sf::Window or sf::RenderWindow instance.
I suggest reading through the tutorials on the SFML website while you're learning the basics. This one is immediately useful.
Related
I need an Algorithm that I will use to scan pixels out from the center. Problem is with different lengths and sizes, it sometimes can't get to the position (See Image below blue part).
To illustrate the problem more I will show the example output:
If you compare the pictures you will notice that it goes in a spiral and the outputs match with a regular for loop and obviously the problem that it doesn't print the blue part correctly
Here is the code:
#include<iostream>
#include<string>
#include<math.h>
int arr[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
int arrSize = sizeof(arr) / sizeof(arr[0]);
int width = 5;
int height = 3;
void normal2DArray() {
int index = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::cout << std::to_string(x) << "," << std::to_string(y) << " = " << std::to_string(arr[index]) << "\n";
index++;
}
}
}
int convertToInex(int x, int y) {
int left = x * y; // elements to the left
int right = (width - x) * y; // elements to the right
return left + right + x;
}
void spiralArray() {
// calculate middle point, which is also the start point
int x = round((float)width / 2) - 1;
int y = round((float)height / 2) - 1;
int direction = 0; // 0=right, 1=up, 2=left, 3=down
int turnCounter = 1;
int numSteps = 1;
int step = 1;
int index;
while (true) {
index = convertToInex(x, y); // defines the index position in arr
std::cout << std::to_string(x) << "," << std::to_string(y) << " = " << std::to_string(arr[index]) << "\n";
switch (direction) {
case 0: x++; break;
case 1: y--; break;
case 2: x--; break;
case 3: y++; break;
}
index = convertToInex(x, y);
if (step % numSteps == 0) {
direction = (direction + 1) % 4;
turnCounter++;
if (turnCounter % 2 == 0) numSteps++;
}
step++;
if (step > arrSize) break;
}
}
void main() {
std::cout << "Output of Normal 2D Array:\n";
normal2DArray();
std::cout << "\n"; // better spacing
std::cout << "Output of Spiral Array:\n";
spiralArray();
}
I tried to keep the code as simple and small as possible. It should be ready to import and use.
And yes I already searched for my answer online but I didn't find anything that covered up the problem here nor had a similar setup like I have(1D arr and combined 2D array WIDTH/HEIGHT) and for sure not in c++.
❗ Also I need a Solution that works with all widths and heights and arr sizes and also works for any side ❗
I hope you can provide me with helpful answers and would be grateful with good and fast algorithm implementations/optimizations
EDIT:
Thanks to the replies in this Thread. I decided to go with the solution from #ldog for now even though I'm not completely satisfied with it.
Here are the edited code parts:
int failcounter = 0;
while (true) {
index = convertToInex(x, y); // defines the index position in arr
if (index < 0 || index > arrSize) failcounter++;
else std::cout << std::to_string(x) << "," << std::to_string(y) << " = " << std::to_string(arr[index]) << "\n";
// unchanged code inbetween
if (step > arrSize + failcounter) break;
Based on your comment:
#Beta they don't need to connect. It just has to detect that it's outside the array size (in that case -1) and don't scan them and find the next continue point. So it would continue like this: 5, 1, 6, 11
it seems you don't care that the spiral goes "out-of-bounds". In this case, the trivial answer is, embed the shapes that have no spiral in one that is always guaranteed to have one.
Thus if your input rectangle is N x M, then embed it in a rectangle of size max(M,N) x max(M,N), solve the problem in the latter, and when printing just ignore non-existent numbers in the original problem. Your printed sequence then will always be unique up to how the embedding occurs. The most reasonable embedding would try to center the smaller rectangle as much as possible in the larger rectangle, but this is up to you.
In this case you don't need an algorithm as you can compute everything analytically if you care to do the book-keeping and figure out the formulas involved.
You can hit a dead end (meaning exit the grid) in four spots. In each case, jump to the next live pixel you would have reached, if any live cells remain.
You can do this fairly easily by keeping track of the four corners you've visited furthest from the starting pixel. Using compass coords and N for up, these are the NE, NW, SW, and SE extremes visited.
If you hit a dead end going N from the NE pixel, jump to the pixel one to the left of the NW pixel and set the movement direction to down. If that is also a dead end, jump to one below the SW pixel and set the movement direction to right. Etc... When all four corners and dead ends then you're done.
I saw that there was another question almost just like this but the answer didn't do what I want it to.
This is for an assignment. I have a 4x4 grid and a users inputted starting and ending (x,y) coordinates. I need to send this info from main to a create_path function which calculates the shortest path then sends it to another function that prints the grid step by step of the markers location until it makes it to the wanted coordinate. I can't use arrays and I have to have main, create_path, and print_path. The marker can only go up, down, left, and right.
So I really have no clue what to do. I thought about creating a variable for each cell in the grid but didn't know where to go from there. If somebody knows a quick solution that only uses main and one other function that is okay because I am running out of time.
You don't need to see main because it just shows the user the grid and asks them for input then sends the input to this function:
void create_path(int xStart, int xEnd, int yStart, int yEnd)
{
}
As you have already pointed out yourself in the comments, the shortest path from (0,2) to (3,1) is "right 3 down 1" in other words: right 3-0=3 and down 2-1=1
And that's already pretty much the answer...
In general, how do find the shortest path from (xStart, yStart) to (xEnd, yEnd)? You just do the same thing as before again. It is "right xEnd-xStart, down yEnd-yStart".
So everything that the print_path function requires is just "where do I start" and "how much do I go right/left and how much do I go up/down?"
So you could use two variable in create_path
int right = xEnd-xStart;
int down = yEnd-yStart;
and you send these to print_path. You have not provided the signature of print_path, but it could look like this:
void print_path(int xStart, int yStart, int right, int down)
{
}
Within this function you just do two loops:
int i = xStart;
int xend = xStart + right; // observe: if right is negative, it's just subtraction
bool right = (right >= 0); // are we going right or left?
while(i != xend) {
std::cout << "next waypoint: x = " << i << ", y = " << yStart << std::endl;
if (right) {
i++;
} else {
i--;
}
}
And now you do the same thing for the y coordinate
int j = yStart;
int yend = yStart + down;
bool down = (down >= 0); // are we going down or up?
while(j != yend) {
std::cout << "next waypoint: x = " << xend << ", y = " << j << std::endl;
if (down) {
j++;
} else {
j--;
}
}
create_path has to be a recursive function.
conditions given should be :
First check if the points are in the boundary or not
Then check if the point is the desired point, if yes then return
Otherwise recurse for up, down, left, right and diagonal points.
So this question is a little more abstract than some. Say I have a game that I only want to render once per second, such as a Tetris clone. I only want to process one input per second, then render the new frame accordingly. Tetris is a grid-based game, so I can't just move the game piece by a certain amount times the timeDelta float that people usually use for frame rate examples. How do I go about only rendering one frame per second in a grid-based game? Here's what code I have so far, but it's wrong:
void Engine::Go(){
while(window.isOpen()){
if(timeElapsed >= 1000){
timeElapsed = clock.restart().asMilliseconds();;
ProcessInput();
}
UpdateCPU();
Render();
timeElapsed = clock.getElapsedTime().asMilliseconds();
time += timeElapsed;
}
}
void Engine::ProcessInput(){
while(window.pollEvent(event)){
if(event.type == (sf::Event::Closed))
window.close();
}
//process movement detection of piece
int temp = level.GetGamePieces().size();
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
level.GetGamePieces().at(temp - 1).GetPieceSprite().move(-10, 0);
std::cout << "left";
moved = true;
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
level.GetGamePieces().at(temp - 1).GetPieceSprite().move(10,0);
std::cout << "right";
moved = true;
}
else{
level.GetGamePieces().at(temp - 1).GetPieceSprite().move(0,10);
std::cout << "down";
moved = true;
}
}
I only want to move the gamepiece one sqaure at a time, once per second, but I just don't know how to do this.
Edit: Here's the code that renders the frames
void Engine::Render(){
window.clear();
//draw wall tiles
for(int i = 0; i < 160; i++){
if(i < 60){
level.GetWallTile().setPosition(0, i * 10);
window.draw(level.GetWallTile());
}
if(i >= 60 && i < 100){
level.GetWallTile().setPosition((i - 60) * 10, 590);
window.draw(level.GetWallTile());
}
if(i >= 100){
level.GetWallTile().setPosition(390, (i - 100) * 10);
window.draw(level.GetWallTile());
}
}
//draw BG tiles
for(int i = 1; i < 39; i++){
for(int j = 0; j < 59; j++){
level.GetBGTile().setPosition(i * 10, j * 10);
window.draw(level.GetBGTile());
}
}
for(int i = 0; i < level.GetGamePieces().size(); i++){
window.draw(level.GetGamePieces()[i].GetPieceSprite());
}
window.display();
}
You are not accounting for the fact that a user may want to move a shape in between movements of the shape.
You should allow the user to move the shape left, right, and down whenever he/she wants to, but
not force the downward movement until after the elapsed time has completed.
When I made a block-based game, here's what I did
void updateSeconds( double deltaTime ) {
// If timer until shape falls runs out, move the shape down.
timeUntilShapeDrop -= deltaTime;
if ( timeUntilShapeDrop > 0 || currentFallingShape->isAnimating() ) {
return;
}
// If ( shape collides with map when moved down )
currentFallingShape->move(-1,0);
if ( currentFallingShape->isCollisionWithMap ( * map ) ) {
currentFallingShape->move(1,0);
// Lock shape in place on the map
currentFallingShape->setBlocksOnMap( * map );
lastUpdateLinesCleared = clearFullLines();
}
timeUntilShapeDrop = calculateShapeDropTimeInterval();
I also included gradual shape animation if you're interested one way of how to do it. I built a graphical game map on top of the logical map and used the logical map to start the graphical interpolation. I broke the graphics library I was using, but the logic code is still good for reference or use if you'd like.
I'm rather new at SFML and I've been playing around with a basic tile engine that I found online. In the tile engine was a camera that did not work all that well and so I took it out with the intent to replace it with my own later. Directly prior to this, the engine would draw only the tiles which were on screen and for some reason was incapable of adding additional tiles to the list of the tiles which need to be drawn. At the current time, I am attempting to draw every tile possible but receiving a vector subscript error after the first row - 1.
Here is the code that seems to be causing the error:
int levelHeight = currentLevel->getHeight();
int levelWidth = currentLevel->getWidth();
for(int tileY = 1; tileY < levelHeight; tileY++)
{
for(int tileX = 1; tileY < levelWidth; tileX++)
{
tile = currentLevel->getTile(tileX, tileY);
std::cout << "Adding Tile X: " << tileX << ", Y: " << tileY << " to buffer." << std::endl;
if(tile)
tile->draw((tileX * tileSize), (tileY * tileSize), display);
}
}
If there is anything else that it would be useful if I provide feel free to ask
I think the inner for loop terminating condition is incorrect:
for(int tileX = 1; tileY < levelWidth; tileX++)
should be:
for(int tileX = 1; tileX < levelWidth; tileX++)
//^
So, I've been trying to create a 'Map' class to handle the drawing of my tile maps on the window but I'm having a problem to draw all the tiles to the screen.
This is my problem: lets say i have a map of 10*10 tiles with 5 layers which sums up to 10*10*5 = 500 tiles ( of course in real time there will be more likely 10 times more tiles which would be worse )... and it is stored in a 3d array [layer][row][col] or chars, each char representing an index on my sprite sheet of tiles
so i created a 'SpriteSheet' class to handle my sprite sheets and get each sprite from the sheet by an index: spriteSheet->GetSubSprite(idx).
so in the end i have something like Draw(spriteSheet->GetSubSprite((int)mapArray[i][j][k])) which should be called for each sprite, EVERY GAME LOOP so lets say my game runs on 60 fps and i have 500 tiles to draw: the game aims to draw 500*60 = 30,000(!) tiles each second...
so as you can see im having abit of a problem here...? anybody knows how to sufficiently in terms of speed imporve this? ( and of course any kind of improvement to my current structure would be very blessed ).
So, just in case here is my SpriteSheet.cpp and my Map.cpp files, I know I have many design mistakes but please focus on my question, the design is far from finished.
#include "Map.h"
sz::Map::Map(std::string path, std::string name, std::string image) : Tmx::Map() {
ParseFile(path);
if (HasError()) {
printf("error code: %d\n", GetErrorCode());
printf("error text: %s\n", GetErrorText().c_str());
system("PAUSE");
}
else {
mapArray = new unsigned char**[GetNumLayers()];
for(int i = 0; i < GetNumLayers(); i++) {
mapArray[i] = new unsigned char*[GetLayer(i)->GetHeight()];
for(int j=0; j<GetLayer(i)->GetHeight(); j++) {
mapArray[i][j] = new unsigned char[GetLayer(i)->GetWidth()];
// [layer][row][col]
}
}
//load the array
for (int i = 0; i < GetNumLayers(); ++i) {
// Get a layer.
const Tmx::Layer *layer = GetLayer(i);
for (int y = 0; y < layer->GetHeight(); ++y) {
for (int x = 0; x < layer->GetWidth(); ++x) {
// Get a tile global id.
mapArray[i][x][y] = (char)layer->GetTileGid(x, y);
//printf("%3d", mapArray[i][x][y]);
/* need to fix later on
/****************************
// Find a tileset for that id.
const Tmx::Tileset *tileset = FindTileset(layer->GetTileGid(x, y));
if (layer->IsTileFlippedHorizontally(x, y)){
printf("h");
}else{
printf(" ");
}
if (layer->IsTileFlippedVertically(x, y)){
printf("v");
}else{
printf(" ");
}
if (layer->IsTileFlippedDiagonally(x, y)){
printf("d ");
} else {
printf(" ");
}
****************************/
}
//printf("\n");
}
//printf("\n\n");
}
}
tiles = new sz::SpriteSheet(name, image, 33, 33);
}
void sz::Map::Draw(sf::RenderWindow *rw) {
// dont know what to do T_T
}
#include "SpriteSheet.h"
sz::SpriteSheet::SpriteSheet(std::string name, std::string path, int tileW, int tileH) : sz::GameObject(name, path) {
this->tileH = tileH;
this->tileW = tileW;
numOfTiles = ((this->GetImage()->GetHeight()) / tileH) * ((this->GetImage()->GetWidth()) / tileW);
}
int sz::SpriteSheet::GetTileWidth() { return tileW; }
int sz::SpriteSheet::GetTileHeight() { return tileH; }
int sz::SpriteSheet::GetNumOfTiles() { return numOfTiles; }
sf::Sprite sz::SpriteSheet::GetSubSprite(int idx) {
if(idx < 1 || idx > numOfTiles) {
std::cout << "Incorrect index!" << std::endl;
// need return value
}
int row=0, col=0, tilesEachRow = (GetImage()->GetWidth() / tileW);
while(idx > tilesEachRow) {
idx -= tilesEachRow;
col++;
}
row = idx-1;
sz::GameObject *sub = new sz::GameObject(name, path);
/*std::cout << "tileW: " << tileW << std::endl;
std::cout << "tileH: " << tileH << std::endl;
std::cout << "row: " << row << std::endl;
std::cout << "col: " << col << std::endl;
std::cout << "tiles per row: " << tilesEachRow << std::endl;
std::cout << "(" << row*tileW << ", " << col*tileH << ", " << (row+1)*tileW << ", " << (col+1)*tileH << ")" << std::endl;*/
sub->SetSubRect(sf::IntRect(row*tileW, col*tileH, (row+1)*tileW, (col+1)*tileH));
return *sub;
}
Are you actually experiencing any speed issues?
While 30,000 tiles per second may sound like a lot, in terms of computing with a more modern PC, it may not be much of a problem.
Having said this, I can definitely think of a way to optimise what you have if outputting a single tile has a certain overhead associated with it (eg. 2 tiles takes longer to output than 1 tile that is the size of both tiles combined). I don't profess to know much in terms of SFML, but I assume there is some sort of surfaces/canvas system in place. What you could do is write a method that draws static tiles to a surface, once. Then output this surface once each frame of the game. This means there is no need to repetitively output tiles every frame in a tile by tile fashion. You just output a single image of all the static tiles combined.
I reckon you could even use this system dynamically. If a tile needs to change, simply overwrite the relevant part of this surface with the updated tile data. In other words, you leave everything that is static alone and only target areas that require updating.
I agree with Alex Z in that with modern/mainstream hardware rendering 5 screens worth of tiles should not be too slow. However the only way to know for sure is to test it.
Also you need to realize that even if your map has 1000x1000 tiles, you will only be rendering 10x10 worth of tiles per frame because the rest of the tiles are outside the screen.
If you want to make your current structure more optimized, you should store each of the sprites in your sprite sheet as seperate sprites in an array. That way you will not need to call SetSubRect everytime you need to access a single tile.