I'm trying to make a game using C++ in SFML for the first time.
Want : 6 blocks fall from random top to bottom.
Result : 1 block stay at the top.
How should I fix in this code?
#include <SFML/Graphics.hpp>
#include <vector>
#include <time.h>
using namespace sf;
using namespace std;
struct Position{
int x;
int y;
};
int main()
{
srand(time(NULL));
RenderWindow window(VideoMode(600, 480), "AVOID BLOCKS");
window.setFramerateLimit(60);
Texture t1, t2;
t1.loadFromFile("images/block.png");
t2.loadFromFile("images/cha2.png");
Sprite block(t1), cha2(t2);
Position blockPos;
blockPos.y = 0 + t1.getSize().y;
cha2.setPosition(300, 400);
float blockSpeed = 4;
const int size = 6;
vector<Sprite> blocks(6);
int n = 0;
auto bsize = t1.getSize();
for (int i = 0; i < 6; i++) {
blocks[n].setTexture(t1);
blocks[n].setPosition(rand()%10*bsize.x, 0);
n++;
}
while (window.isOpen())
{
Event e;
while (window.pollEvent(e)) {
if (e.type == Event::Closed)
window.close();
}
auto cha2_pos = cha2.getPosition();
if (Keyboard::isKeyPressed(Keyboard::Left)) {
if (cha2.getPosition().x < 0)
continue;
cha2.move(-5.0, 0.0);
}
if (Keyboard::isKeyPressed(Keyboard::Right)) {
if (cha2.getPosition().x > 600)
continue;
cha2.move(5.0, 0.0);
}
if (blockPos.y >= 480) {
blockPos.y = 0 + t1.getSize().y;
blockSpeed = blockSpeed + 0.2;
}
else
blockPos.y += blockSpeed;
for (int i = 0; i < blocks.size(); i++) {
if (FloatRect(cha2_pos.x + 3, cha2_pos.y + 3, 10, 10).
intersects(blocks[i].getGlobalBounds())) {
window.close();
}
}
window.clear();
window.draw(block);
window.draw(cha2);
window.display();
}
return 0;
}
The character at the bottom moves well.
I have no idea why block doesn't move and there's only one.
I think there's something wrong in the part starts "const int size".
Your program have two main problems. First of all, you don't draw all the blocks in the vector but you draw only the particular block you have made. This is why you see only one block on screen and not all the blocks you have create. The solution for this is:
for(auto& blk : blocks)
window.draw(blk);
The second problem affects the movement of the blocks. You have create a struct Position but you never associated with the blocks. So after you increase blockPos.y, you must move the blocks at that new blockPos.y. Explicit:
for(auto& blk : blocks)
blk.setPosition(blockPos.x, blockPos.y);
In this way you will have the problem that every block will be in the exact same position with the others because the blockPos variable is common for all blocks. A good idea is to make a class Block so which block to have his own position and movement. An example to what I say is:
class Block {
private:
Sprite block;
Position blockPos;
public:
Block(Texture& texture, int x, int y)
{
block.setTexture(texture);
blockPos.y = y;
blockPos.x = x; // save this value because you will need it
// every time you move the block
}
void setBlockPosition(float y)
{
blockPos.y = y;
}
Vector2<float> getBlockPosition()
{
return Vector2f(blockPos.x, blockPos.y);
}
void blockMovement(int y)
{
blockPos.y += y;
block.setPosition(blockPos.x, blockPos.y);
}
Sprite getSprite()
{
return block;
}
void Draw(RenderWindow& window)
{
window.draw(block);
}
};
After that I declare a vector with the new dynamic objects:
vector<Block*> blocks(6);
for(unsigned int i = 0; i < blocks.size(); i++)
{
blocks[i] = new Block(t1, rand()%10*t1.getSize().x ,0 - t1.getSize().y);
}
I change your if statements also:
for(unsigned int i = 0; i < blocks.size(); i++) //check for which block in the vector
{
if (blocks[i]->getBlockPosition().y >= 480) {
blocks[i]->setBlockPosition(0 - 200);
blockSpeed = blockSpeed + 0.2;
}
else {
blocks[i]->blockMovement(blockSpeed);
}
}
for (unsigned int i = 0; i < blocks.size(); i++) {
if (FloatRect(cha2_pos.x + 3, cha2_pos.y + 3, 10, 10)
.intersects(blocks[i]->getSprite().getGlobalBounds())) {
window.close();
}
}
Don't forget at the end to delete the objects because they was allocate dynamically:
for(unsigned int i = 0; i < blocks.size(); i++)
delete blocks[i];
return 0;
Related
so recently I have been wanting to make a snake game in C++ using SFML in Microsoft Visual studio 2015 and I made one and I am actually pretty satisfied with my work but there is a problem, that I forgot to make a game over for it and it seems like I couldn't make it work and it really had me on edge. So I thought I could use stack overflow's help. I would really appreciate it if you guys would let me know how to make it work and please keep it simple obvious.
Here is my code:
// GraphicalLoopSnakeGame.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <ctime>
#include <SFML/Graphics.hpp>
using namespace sf;
int N = 30, M = 20;
int size = 16;
int w = size * N;
int h = size * M;
int dir, num = 4;
struct Snake {
int x, y;
} s[100];
struct Fruit {
int x, y;
} f;
void Tick() {
for(int i = num; i > 0; --i) {
s[i].x = s[i - 1].x;
s[i].y = s[i - 1].y;
}
if(dir == 0) s[0].y += 1;
if(dir == 1) s[0].x -= 1;
if(dir == 2) s[0].x += 1;
if(dir == 3) s[0].y -= 1;
if((s[0].x == f.x) && (s[0].y == f.y)) {
num++;
f.x = rand() % N;
f.y = rand() % M;
}
if(s[0].x > N) s[0].x = 0;
if(s[0].x < 0) s[0].x = N;
if(s[0].y > M) s[0].y = 0;
if(s[0].y < 0) s[0].y = M;
for(int i = 1; i < num; i++)
if(s[0].x == s[i].x && s[0].y == s[i].y) num = i;
}
int main() {
srand(time(0));
RenderWindow window(VideoMode(w, h), "Snake Game!");
Texture t1, t2, t3;
t1.loadFromFile("images/white.png");
t2.loadFromFile("images/red.png");
t3.loadFromFile("images/green.png");
Sprite sprite1(t1);
Sprite sprite2(t2);
Sprite sprite3(t3);
Clock clock;
float timer = 0, delay = 0.13;
f.x = 10;
f.y = 10;
while(window.isOpen()) {
float time = clock.getElapsedTime().asSeconds();
clock.restart();
timer += time;
Event e;
while(window.pollEvent(e)) {
if(e.type == Event::Closed) window.close();
}
if(Keyboard::isKeyPressed(Keyboard::Left)) dir = 1;
if(Keyboard::isKeyPressed(Keyboard::Right)) dir = 2;
if(Keyboard::isKeyPressed(Keyboard::Up)) dir = 3;
if(Keyboard::isKeyPressed(Keyboard::Down)) dir = 0;
if(Keyboard::isKeyPressed(Keyboard::W)) dir = 3;
if(Keyboard::isKeyPressed(Keyboard::D)) dir = 2;
if(Keyboard::isKeyPressed(Keyboard::A)) dir = 1;
if(Keyboard::isKeyPressed(Keyboard::S)) dir = 0;
if(timer > delay) {
timer = 0;
Tick();
}
////// draw ///////
window.clear();
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++) {
sprite1.setPosition(i * size, j * size);
window.draw(sprite1);
}
for(int i = 0; i < num; i++) {
sprite2.setPosition(s[i].x * size, s[i].y * size);
window.draw(sprite2);
}
sprite3.setPosition(f.x * size, f.y * size);
window.draw(sprite3);
window.display();
}
return 0;
}
In your Tick() function you can check whether the head bumps into anything after everything has moved in the given direction. If it does, let main() know about it somehow: for example, return a bool which expresses if the game is over. Let's say this bool is called over.
So, add if (over) { window.close(); } inside your while (window.isOpen()) loop (right after calling Tick()) to let main() reach return 0; and finish the program.
EDIT: Think about using std::deque for moving your snake using less code and time: you'd be able to just pop_back() the snake tile farthest from the head and push_front() the new tile where the head currently is (after a tick), simulating crawling one step forwards.
Anyway, after having moved your snake you can check each of its body tiles whether it has the same coordinates as its head. If it does, it means your snake crashed into its tail so the game is over.
// in Tick():
// ...other logic...
tiles.pop_back();
tiles.push_front(new_head_position);
for (/* each tile of your snake except its head */) {
if (tile.x == head.x && tile.y == head.y) {
return false; // game over
}
}
return true; // everything is fine
So my now completed program works as intended apart from one crash that happens when i keypress 'p' which should only switch an if statement to the else part, however it crashes with the "illegal instruction (core dumped)" message.
#include <stdio.h>
// include the UFCFGL301's standard library
#include <ufcfgl-30-1.h>
// uncomment if you want to use the graphics library
#include <graphics.h>
const uint32 window_Width = 600;
const uint32 window_Height = 400;
using namespace uwe;
struct Rect{
int x,y,width,height,r,g,b;
};
struct Circle{
int x,y,radius,r,g,b;
};
union CircleorRect{
Rect rect;
Circle circle;
};
Rect createRect() {
int x = rand() % window_Width;
int y = rand() % window_Height;
int width = rand() % 200;
int height = rand() % 200;
int r = rand()%256;
int g = rand()%256;
int b = rand()%256;
return Rect{x, y, width, height, r, g, b};
};
Circle createCirc() {
int x = rand() % window_Width;
int y = rand() % window_Height;
int radius = rand() % 200;
int r = rand()%256;
int g = rand()%256;
int b = rand()%256;
return Circle{x, y, radius, r, g, b};
};
Rect createRect();
Circle createCirc();
int main(void) {
// graphics window
initialiseGraphics(window_Width,window_Height);
// variables
int count = 0,pressedcount;
Circle circle[1000];
Rect rects[1000];
bool stopCircs = false;
// creating distinct shapes then mapping them.
loop(
[&](){
rects[count] = createRect();
//if circles = create new circle and paint it
if (stopCircs == false) {
circle[count] = createCirc();
for (size_t i = 0; i < count; i++) {
setColour(circle[i].r,circle[i].g,circle[i].b);
drawFilledCircle(circle[i].x,circle[i].y,circle[i].radius);
}
}
else {
for (size_t i = 0; i < pressedcount; i++) {
setColour(circle[i].r,circle[i].g,circle[i].b);
drawFilledCircle(circle[i].x,circle[i].y,circle[i].radius);
}}
for (size_t i = 0; i < count; i++) {
setColour(rects[i].r,rects[i].g,rects[i].b);
drawFilledRect(rects[i].x,rects[i].y,rects[i].width,rects[i].height);
}
count++;
if (count >= 1000) {
count = 0;
}
},
[&](KeyPress keyPress){
if (getTextCharacter(keyPress) == 'q') {
return true;
}
else if (getTextCharacter(keyPress) == 'p') {
stopCircs = true;
pressedcount = count;
}
else {
return false;
}
});
return 0;
}
The 'p' press should only switch from generating new circles to just loading the older ones, no idea why it causes a crash.
This is the whole thing so if anyone wants to try and run it or tell me how to get a better debugger than trying and failing any help would be appreciated.
In this lambda not all control-paths have a return statement (compiling with a higher error/warning level might diagnose this kind of error).
[&](KeyPress keyPress){
if (getTextCharacter(keyPress) == 'q') {
return true;
}
else if (getTextCharacter(keyPress) == 'p') {
stopCircs = true;
pressedcount = count;
//here maybe missing return
}
else {
return false;
}
// or here maybe missing return
}
class Tile : public sf::RectangleShape {
public:
Tile();
Tile(float);
~Tile();
void highlightTile();
bool isTileHighlighted() const;
void turnOffHighlight();
private:
sf::RectangleShape m_tile;
bool m_isHighlighted;
};
Tile::Tile()
{
}
Tile::Tile(float squareDim) : m_tile(sf::Vector2f(squareDim, squareDim)), m_isHighlighted(false) {
}
bool Tile::isTileHighlighted() const {
return (m_tile.getOutlineColor() == sf::Color::Yellow);
}
void Tile::turnOffHighlight(){
m_tile.setOutlineThickness(0);
}
void Tile::highlightTile() {
m_tile.setOutlineThickness(5);
m_tile.setOutlineColor(sf::Color::Yellow);
}
Tile::~Tile(){
}
Grid::Grid(float squareDim)
{
Tile tilePiece(squareDim);
sf::Vector2f position(0, 0);
int counter = 0; //counter for whether the column is even or odd
int counter1 = 0; //counter for whether we are on an even or odd row
for (int row = 0; row < 8; row++) {
for (int column = 0; column < 8; column++) {
if (counter1 % 2 == 0 && counter % 2 == 0 || counter1 % 2 != 0 && counter % 2 != 0) {
tilePiece.setFillColor(sf::Color::Red);
}
else {
tilePiece.setFillColor(sf::Color::White);
}
tilePiece.setPosition(position);
m_tileSet[row][column] = tilePiece; //correct coordinates
m_gridMap[row][column] = sf::Vector2f(tilePiece.getPosition().x + squareDim / 2, tilePiece.getPosition().y + squareDim / 2);
position.x += squareDim;
counter++;
}
position.y += squareDim;
position.x = 0;
counter = 0;
counter1++;
}
}
The tiles are not rendering. I'm not sure the issue or whether I'm doing something wrong with the inheritance here and whether I should have the m_tile and that makes sense..
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
You are trying to draw Tile object (I suppose so, as you did not show us code which draws). But you never set its dimensions, that's why you can't see it. What you do is to set dimensions for member variable ( m_tile(sf::Vector2f(squareDim, squareDim)) ) which is not used if you draw Tiles like this: window.draw(tile).
You have to choose: either inherit publicly from RectangleShape or contain member object RectangleShape, not both.
Okay so I am a college student and our professor gave us this code to examine, and I was wondering if there was another way to do this but for OS X. My professor is using a HANDLE which I barely understand what that is, the professor was telling me he create the HANDLE as a pointer to the output stream so what would be the equivalent to it for mac since we don't have #include Windows.h obviously. Everything you see in this code is my professor's, including the comments.
//This is an example of a simple platformer made in the console. This
//makes no claims as the best way of doing things as I created this
//live before a class (while taking suggestions from them).
#include <iostream>
#include <string>
#include <vector>
#include <Windows.h>
using namespace std;
const int MAX_ROWS = 20;
const int MAX_COLS = 60;
//this is a reference to cout (we got this when we changed the output color)
//we can use this to setCursorPosition
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
//this is the place that we can set the cursor to when we are not using it
COORD zero;
//basic cardinal directions
enum Direction
{
UP = 8,
DOWN = 2,
RIGHT = 6,
LEFT = 4,
NORTH = UP,
SOUTH = DOWN,
EAST = RIGHT,
WEST = LEFT
};
//each place on the gameboard is a tile (tiles in this game are 1 character in length, though they do not have to be)
class Tile
{
public:
char display;
bool isPassible;
COORD pos;
Tile(char d, bool b, int y, int x)
{
display = d;
isPassible = b;
pos.X = x;
pos.Y = y;
}
void Display()
{
SetConsoleCursorPosition(output, pos);
cout << display;
SetConsoleCursorPosition(output, zero);
}
};
class Player
{
public:
COORD pos;
char display;
int JumpAmt;
//player constructor (x and y are starting location)
Player(int x, int y)
{
pos.X = x;
pos.Y = y;
display = 'C';
JumpAmt = 0;
}
//This gets the input and decides how to use it (this should be called in the main game loop)
bool Act(vector<vector<Tile>> GameBoard)
{
bool didMove = false;
COORD oldPos;
oldPos.X = pos.X;
oldPos.Y = pos.Y;
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
{
//make sure the movement is not off the game board and that there is not a wall in the way
if (pos.X + 1 < MAX_COLS && GameBoard[pos.Y][pos.X + 1].isPassible)
{
//actually move the character
pos.X += 1;
didMove = true;
}
}
if (GetAsyncKeyState(VK_LEFT) & 0x8000)
{
if (pos.X - 1 > 0 && GameBoard[pos.Y][pos.X - 1].isPassible)
{
pos.X -= 1;
didMove = true;
}
}
//You can only jump if you are on the ground
if (pos.Y + 1 < MAX_ROWS && !(GameBoard[pos.Y + 1][pos.X].isPassible))
{
if (GetAsyncKeyState(VK_UP) & 0x8000)
{
if (pos.Y - 1 > 0 && GameBoard[pos.Y - 1][pos.X].isPassible)
{
pos.Y -= 1;
didMove = true;
JumpAmt = 4;
}
}
}
//When you are not jumping fall (gravity)
if (JumpAmt == 0)
{
if (pos.Y + 1 < MAX_ROWS && GameBoard[pos.Y + 1][pos.X].isPassible)
{
pos.Y += 1;
didMove = true;
}
}
//This is what happens during your jump
if (JumpAmt > 0)
{
JumpAmt--;
if (pos.Y - 1 > 0 && GameBoard[pos.Y - 1][pos.X].isPassible)
{
pos.Y -= 1;
didMove = true;
}
}
//If you did move anywhere then update the board
if (didMove)
{
Display(oldPos, GameBoard);
}
return didMove;
}
void Display()
{
//draw myself at my position
SetConsoleCursorPosition(output, pos);
cout << display;
SetConsoleCursorPosition(output, zero);
}
void Display(COORD fix, vector<vector<Tile>> GameBoard)
{
//clear my old position
GameBoard[fix.Y][fix.X].Display();
Display();
}
};
int main()
{
//zero is used after anything is drawn to reset the cursor (this should never be changed after this)
zero.X = 0;
zero.Y = 0;
//this is a 2 dimentional array of tiles
vector<vector<Tile>> GameBoard;
//init all the tiles to blank (we will later add in platforms and stuff over top of these)
for (int row = 0; row < MAX_ROWS; row++)
{
vector<Tile> thisRow;
for (int col = 0; col < MAX_COLS; col++)
{
thisRow.push_back(Tile(' ', true, row, col));
}
GameBoard.push_back(thisRow);
}
//Build the game specific tiles (in a perfect world these would be read in from a file)
GameBoard[4][2] = Tile('-', false,4,2);
GameBoard[4][3] = Tile('-', false, 4,3);
GameBoard[4][4] = Tile('-', false, 4,4);
GameBoard[4][5] = Tile('-', false, 4,5);
GameBoard[4][6] = Tile('-', false, 4,6);
GameBoard[7][9] = Tile('-', false, 7,9);
GameBoard[7][10] = Tile('-', false, 7,10);
GameBoard[5][10] = Tile('-', false, 5,10);
GameBoard[8][14] = Tile('*', false, 8, 14); //this marks the win square
//display the board once
for (int row = 0; row < MAX_ROWS; row++)
{
for (int col = 0; col < MAX_COLS; col++)
{
GameBoard[row][col].Display();
}
}
//Bob is our hero
Player bob = Player(3, 3);
while (true)
{
bob.Act(GameBoard);
bob.Display();
Sleep(50);
//if bob falls down he dies
if (bob.pos.Y > 18)
{
bob.pos.X = 3;
bob.pos.Y = 3;
//bob.display = 65 + rand() % 26;
}
//if bob gets here he wins
if (bob.pos.Y == 7 && bob.pos.X == 14)
{
COORD pos;
pos.Y = 20;
pos.X = 0;
SetConsoleCursorPosition(output, pos);
cout << "You are Awesome";
break;
}
}
COORD pos;
pos.Y = 21;
pos.X = 0;
SetConsoleCursorPosition(output, pos);
system("Pause");
return 0;
}
At the moment I am building a cloth physics app using OpenFrameworks. I'm new to C++, for a heads up.
In my app, two 'neighbor' particle objects are passed to a spring object as pointers. As a test, I have the spring object draw lines between the two particles (between their 3d vector positions). For some reason, these lines are different every time I run the program, even though no random values are involved. When I cout the values of the particle positions from the spring struct, they often are ridiculous values like -4.15301e-12. I'm following example code almost verbatim, so I'm not really sure where I'm going wrong.
Here is the example code I'm following:
https://sites.google.com/site/ofauckland/examples/17-cloth-physics
Here is my Spring struct:
#pragma once
#include "ofMain.h"
#include "Particle.h"
struct Spring {
float k, restLength;
Particle *a, *b;
ofVec3f posA, posB;
Spring(Particle *a, Particle *b, float k = .2) : a(a), b(b), k(k) {
restLength = (b->pos - a->pos).length();
}
void update() {
posA = a->pos;
posB = b->pos;
}
void draw() {
ofSetLineWidth(5);
ofSetColor(0, 255, 0);
ofLine(posA.x, posA.y, posB.x, posB.y);
}
};
The particle struct:
#pragma once
#include "ofMain.h"
struct Particle {
ofVec3f pos;
Particle(ofVec3f pos) : pos(pos) {
}
void update() {
}
void draw() {
ofSetColor(ofRandom(255), 0, 0);
ofFill();
ofCircle(pos.x, pos.y, 3);
}
};
And this is where I pass the two particles to the spring as pointers:
#pragma once
#include "ofMain.h"
#include "Particle.h"
#include "Spring.h"
struct Petal {
float maxWidth, spacing;
vector<Particle> particles;
vector<Spring> springs;
Petal(float maxWidth, float spacing) : maxWidth(maxWidth), spacing(spacing) {
setupPoints();
}
void setupPoints() {
float x = 0;
float y = 0;
for(int r = 1; r <= maxWidth; r++) {
x = (int)(r / 2) * -spacing;
y += spacing;
for(int c = 1; c <= r; c++) {
ofVec3f pos = ofVec3f(x, y, 0);
Particle p(pos);
particles.push_back(p);
x+=spacing;
}
}
for(int r = maxWidth; r > 0; r--) {
x = (int)(r / 2) * -spacing;
y += spacing;
for(int c = 1; c <= r; c++) {
ofVec3f pos = ofVec3f(x, y, 0);
Particle p(pos);
particles.push_back(p);
x+=spacing;
}
}
//find neighbors
for(int i = 0; i < particles.size(); i++) {
Spring s(&particles[i], &particles[findNeighbor(i)]);
springs.push_back(s);
}
}
int findNeighbor(int pIndex) {
float leastDist = 0;
float leastDistIndex = 0;
for(int i = 0; i < particles.size(); i++) {
if(i != pIndex) {
float distance = particles[pIndex].pos.distance(particles[i].pos);
if(abs(distance) < abs(leastDist) || leastDist == 0) {
leastDist = distance;
leastDistIndex = i;
}
}
}
return leastDistIndex;
}
void update() {
for(int i = 0; i < particles.size(); i++) {
particles[i].update();
}
for(int s = 0; s < springs.size(); s++) {
springs[s].update();
}
}
void draw() {
for(int i = 0; i < particles.size(); i++) {
particles[i].draw();
}
for(int s = 0; s < springs.size(); s++) {
springs[s].draw();
}
}
};
This is what happens. What's strange is that some of the springs seem to be in the correct position.
Please let me know if I can clarify something.
Thanks!
Your particles vector holds Particles by value, and the vector can copy and move these values around. When you pass Particles as pointers to the Spring, you are passing the address of something that might not be there at some point in the future. I am not sure if this is the problem, but it certainly is something that needs fixing.