Why doesn't the Player.x and Player.y variables change? - c++

Edit #2: Ok, I did another *.cpp to check if the codes for Arrow Keys were right. Doing that, I noticed keyPressed variable in detectKeyPressing() had the wrong type of variable, so I changed it from char to int and changed the codes.
Once I did that, it worked. Now I have put the limits, so the Player cannot go outside the square. But I have another problem, the movement is too tough and if you press the keys too fast, the instructions run with a annoying delay. I know I should use either Sleep(ms) or Delay(ms), but I don't know when I should use it.
This is the new code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing() {
// 0: Escape
// 1: Enter
//2: Up
// 3: Left
// 4: Down
// 5: Right
int keyPressed = 0;
while (keyPressed != 27) {
if (keyPressed == 0 || keyPressed == 224) {
keyPressed = _getch(); //First value of _getch() when any of the arrow keys are pressed is "224", the next one is the code depending of which arrow you pressed
}
else if (keyPressed == 13) {
return 1;
}
else {
switch (keyPressed) {
//Up
case 72:
return 2;
break;
//Left
case 75:
return 3;
break;
//Down
case 80:
return 4;
break;
//Right
case 77:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu() {
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY) {
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main() {
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 1;
cci.bVisible = FALSE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 1;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); // Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
switch (pressedKey) {
//Up
case 2:
Sleep(200);
if (Player.y == Player.speed) {
Player.y = Player.speed; //Top Limit
}
else {
Player.y -= Player.speed;
}
break;
//Left
case 3:
Sleep(200);
if (Player.x == Player.speed) {
Player.x = Player.speed; //Left Limit
}
else {
Player.x -= Player.speed;
}
break;
//Down
case 4:
Sleep(200);
if (Player.y == 30 - Player.speed) {
Player.y = 30 - Player.speed; //Bottom Limit
}
else {
Player.y += Player.speed;
}
break;
//Right
case 5:
Sleep(200);
if (Player.x == 78 - Player.speed) {
Player.x = 78 - Player.speed; //Right Limit
}
else {
Player.x += Player.speed;
}
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x or Player.y modified
};
};
};
return 0;
};
Edit #1: I fixed the mistakes you told me, here's the main function modified. It isn't working though.
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = FALSE; //Changed "TRUE" to "FALSE"
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); //Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
cout << "There's no problem in Else If statement"; //Couts made for testing
switch (pressedKey) {
cout << "There's no problem in Switch statement";
//Up
case 2:
Player.y -= Player.speed;
cout << "You moved Up";
break;
//Left
case 3:
Player.x -= Player.speed; //Fixed Left movement
cout << "You moved Left";
break;
//Down
case 4:
Player.y += Player.speed;
cout << "You moved Down";
break;
//Right
case 5:
Player.x += Player.speed;
cout << "You moved Right";
break;
};
//system("cls"); //Erase all
//draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
Initial Post: I'm trying to do something like an Undertale normal fight and now I'm doing the "dodging attacks" part, but I'm stuck at making the player move (Yep, that "a") because it didn't update when I press an arrow key (for movement). It is supposed to draw, and put the Player in Player.x and Player.y, so I did something in main() to edit these variables depending on the arrow key you pressed, and then erase and re-draw with the Player.x or Player.y modified.
Here's the code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing(){
// 0: Escape
// 1: Enter
// 2: Up
// 3: Left
// 4: Down
// 5: Right
char keyPressed = 0;
while (keyPressed != 27){
if(keyPressed == 0){
keyPressed = _getch();
}
else if(keyPressed == 13){
return 1;
}
else{
switch (keyPressed) {
//Up
case 65:
return 2;
break;
//Left
case 68:
return 3;
break;
//Down
case 66:
return 4;
break;
//Right
case 67:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu(){
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY){
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = TRUE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (detectKeyPressing() == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (detectKeyPressing() > 1 && detectKeyPressing() < 6) {
switch (detectKeyPressing()) {
//Up
case 2:
Player.y -= Player.speed;
break;
//Left
case 3:
Player.x += Player.speed;
break;
//Down
case 4:
Player.y += Player.speed;
break;
//Right
case 5:
Player.x += Player.speed;
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
I did a few tests and it seems that the else if in "//If any of the Arrow Keys is Pressed" part isn't running but I don't know why.
I would really appreciate any help you can provide. Sorry if anything isn't well written, I'm not a native english speaker.

Where you have this comment
//Draw if proyectile is moving - not yet add a variable to save your pressed key, something like
int pressedKey = detectKeyPressing();
Then, use that variable to check which condition is met within your if-else.
What’s happening is that you’re calling your function, thus asking/waiting for an input each time a condition is being checked.

Related

Detecting Walls in Multidimensional Arrays C++ Issues

I need some help figuring this out. For some reason, when I move along
my array say for example "e" for east, I have made a detect wall
collision so the player can't go any further. However, when I try to
go "w" for west (back) it goes back 2 instead of 1. Any ideas on how
to fix this?
For now, use the e button to go right and west button to go left. I've used a multidimensional array and a switch to detect what room you're in, also providing player coordinates.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <windows.h>
using namespace std;
int playerX = 0; // x
int playerY = 0; // y
int nextX; // pY
int nextY; // pX
bool win = false;
string move;
char dungeon[11][11] = {
{ 's','c','c','c','r','w','c','c','c','r','r',},
{ 'w','w','w','c','w','r','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',},
{ 's','c','c','r','r','c','c','c','c','r','r',}
};
void movePlayer();
void location(int X, int Y);
int main()
{
do {
movePlayer();
location(playerX, playerY);
} while (win == false);
}
void movePlayer() {
string move;
cin >> move;
// reference Grid-Cave-Mk1 Author: Heather Southall Date: 2017
if (move == "n") {
nextY = playerY - 1;
if ((nextY >= 0) && (nextY < 11)) {
playerY = nextY;
}
else {
cout << "Can't move there" << endl;
}
}
else if (move == "e") {
nextX = playerX + 1;
if ((nextX >= 0) && (nextX < 11)) {
playerX = nextX;
}
else {
cout << "Can't move there" << endl;
}
}
else if (move == "w") {
nextX = playerX - 1;
if ((nextX >= 0) && (nextX < 11)) {
playerX = nextX;
}
else {
cout << "Can't move there" << endl;
}
}
else if (move == "s") {
nextY = playerY + 1;
if ((nextY >= 0) && (nextY < 11)) {
playerY = nextY;
}
else {
cout << "Can't move there" << endl;
}
}
}
void location(int X, int Y) {
cout << "X: " << X << endl;
cout << "Y: " << Y << endl;
char local = dungeon[Y][X];
switch (local) {
case 's':
cout << "Starter Room" << endl;
break;
case 'c':
cout << "Corridor" << endl;
break;
case 'r':
cout << "Room" << endl;
break;
case 'w':
nextX = playerX - 1;
if ((nextX >= 0) && (nextX < 11)) {
playerX = nextX; playerY = nextY;
break;
}
}
}
Its an issue with misleading logs - you don't print the current position, but the one which "type" is being checked. So you can get to logs [5, 0] and [3, 0] when:
You move east from the [4, 0] room. You check what's at [5, 0] (first print). You hit a wall, so the current position is moved back to [4, 0].
Discouraged, you move west. You check what's at [3, 0] (second print).
You should change the printed message, so that the user is notified about both the current position, and the tested one.
ps. hitting a wall should move you to the previous location instead of translating the position by [-1, 0].

I made a moving screensaver in c++ console but there is a bug when it hits the corner

you know the screensavers on old dvd players? I made it in the console using ascii but when it hits a corner it goes out of sight. I'm not sure what is happening, it should work. I'm just messing around and trying to learn so it's not a big deal but if anyone is interested in taking a look I would be very grateful! Also any general feedback and advice would be appreciated.
#include <iostream>
#include <windows.h>
using namespace std;
int width = 20;
int height = 10;
int iconX, iconY;
enum eDirection {UPLEFT,UPRIGHT,DOWNRIGHT,DOWNLEFT}dir;
int lastDir;
void Setup()
{
dir = UPRIGHT; //sets the direction and a
iconX = rand() % width + 1; //random starting point
iconY = rand() % height + 1;
}
void Draw()
{
system("cls");//clear the screen each frame
for (int y = 0; y < height + 2; y++) { // this goes from top to bottom of the grid
for (int x = 0; x < width + 2; x++) { // and then left to right to hit every square with these conditionals
if (y == 0 || y == height + 1) cout << "-"; //top and bottom border
if ((x == 0 || x == width + 1) && (y != 0 && y != height + 1)) cout << "|"; // both sides
if (x == iconX && y == iconY) cout << "0"; // this is the icon that will bounce around the screen
else if ((y != 0 && y != height + 1) && (x != 0 && x != width+1)) cout << " "; // if the icon wasn't drawn and
} //we aren't currently on a border it makes a space
cout << endl;
}
}
void Move()
{ //bounces on the sides
if (iconX == 1 || iconX == width) {
switch (lastDir) {
case 0:
dir = UPRIGHT; //this code checks if the icon is right
break; //next to a wall and depending on which
case 1: //direction it was moving it is given a
dir = UPLEFT; //new direction to move in
break;
case 2:
dir = DOWNLEFT;
break;
case 3:
dir = DOWNRIGHT;
break;
}
}
//bounces on the top and bottom
if (iconY == 1 || iconY == height) {
switch (lastDir) {
case 0:
dir = DOWNLEFT; //same thing down here but for
break; //the top and bottom
case 1:
dir = DOWNRIGHT;
break;
case 2:
dir = UPRIGHT;
break;
case 3:
dir = UPLEFT;
break;
}
}
switch (dir) {
case UPLEFT:
iconX--; //this code moves the icon
iconY--; //depending on which direction
break; //is currently saved in dir
case UPRIGHT:
iconX++;
iconY--;
break;
case DOWNLEFT:
iconX--;
iconY++;
break;
case DOWNRIGHT:
iconX++;
iconY++;
break;
}
lastDir = dir; //it saves the last direction
} //as a number to be used to do
//the bouncing
int main()
{
Setup();
while (true) {
Draw();
Move();
}
}
she's fixed! check her out. shout out to #JaMiT for the idea
#include <iostream>
#include <windows.h>
using namespace std;
int width = 20;
int height = 10;
int iconX, iconY;
enum Vertical {UP,DOWN}vert;
enum Horizontal {LEFT,RIGHT}hor;
int lastVert;
int lastHor;
void Setup()
{
vert = UP; //sets the direction and a
hor = LEFT;
iconX = rand() % width + 1; //random starting point
iconY = rand() % height + 1;
}
void Draw()
{
system("cls");//clear the screen each frame
for (int y = 0; y < height + 2; y++) { // this goes from top to bottom of the grid
for (int x = 0; x < width + 2; x++) { // and then left to right to hit every square with these conditionals
if (y == 0 || y == height + 1) cout << "-"; //top and bottom border
if ((x == 0 || x == width + 1) && (y != 0 && y != height + 1)) cout << "|"; // both sides
if (x == iconX && y == iconY) cout << "0"; // this is the icon that will bounce around the screen
else if ((y != 0 && y != height + 1) && (x != 0 && x != width+1)) cout << " "; // if the icon wasn't drawn and
} //we aren't currently on a border it makes a space
cout << endl;
}
}
void Move()
{
if (iconX == 1 || iconX == width)
if (lastHor == 0) //0 is left
hor = RIGHT;
else
hor = LEFT;
if (iconY == 1 || iconY == height)
if (lastVert == 0) //0 is up
vert = DOWN;
else
vert = UP;
if (vert == UP)iconY--;
else iconY++;
if (hor == LEFT)iconX--;
else iconX++;
lastVert = vert;
lastHor = hor;
}
int main()
{
Setup();
while (true) {
Draw();
Move();
}
}

My character going left but not going right (CONSOLE GAME)

I working on my project this project have a frame to [100] x [25] matrix and i try to add animation but my character is going left but it's not going right.
i tried with "counter" variable but its not work.
int counter = 1;
int counter2 = 1;
int left_border = 1;
int matris1 = sizeof(map)/100;
int matris2 = sizeof(map[0])/4;
int startx = 19;
int starty = 8;
while (true)
...
int right = 0, left = 0;
...
for (int a = 0; a < matris2; a++)
cout << "\n#"; //i have this because i make it square map.
for (int k = 0; k < matris1 - 2; k++)
{
if (left == 1)
{
if (((startx+2)-counter) == left_border)
{
counter = 0;
//cout << "SINIR!!"<< endl ;
}
if (k == (startx-counter) and a == starty)
{
counter += 1;
cout << "O";
}
else {
cout << " ";
}
}
else if (right == 1)
{
if (k == (startx+counter2) and a == starty)
{
counter2 += 1;
cout << "O";
}
its need to be going right but its not.
if you need full code.
https://codeshare.io/UbKVU
[![This is the map and "O" is the character]
https://i.stack.imgur.com/uyGQo.png
The code is very difficult to follow - you should have a coordinate system. I've made a simple example below. Update the player coordinate when a key is pressed and redraw the map x by y position, if the player is there then draw the 'O', otherwise if its a wall draw an 'X' (in this case), otherwise draw a space ' '.
using namespace std;
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#define MAPW 15 // map width
#define MAPH 15 // map height
int map[MAPW][MAPH];
#define WALL 1
#define EMPTY 0
void initmap()
{
// just set the map to have walls around the border
for (int x = 0; x < MAPW; x++)
{
for (int y = 0; y < MAPH; y++)
{
if (x == 0 || y == 0 || x == (MAPW - 1) || y == (MAPH - 1))
map[x][y] = WALL;
else
map[x][y] = EMPTY;
}
}
}
int px = MAPW / 2; // player x
int py = MAPH / 2; // player y
void main()
{
initmap(); // initialize map
cout << "Press A/W/S/D to begin and move";
while (1)
{
if (kbhit()) // key pressed?
{
switch (getch()) // which key?
{
case 'a':
if (px > 0 && map[px - 1][py] != WALL) // can go left?
px--; // update x coordinate
break;
case 'd':
if (px < (MAPW-1) && map[px + 1][py] != WALL) // can go right?
px++; // update x coordinate
break;
case 'w':
if (py > 0 && map[px][py - 1] != WALL) // can go up?
py--; // update y coordinate
break;
case 's':
if (py < MAPH && map[px][py + 1] != WALL) // can go down?
py++; // update y coordinate
break;
}
// update map - clear screen and redraw
system("CLS");
// draw map each line
for (int y = 0; y < MAPH; y++)
{
for (int x = 0; x < MAPW; x++)
{
// its a wall?
if (map[x][y] == WALL)
cout << "X";
else
{
// is the player there?
if (x == px && y == py)
{
// draw the player
cout << "O";
}
else // empty space
cout << " ";
}
}
// next line
cout << "\n";
}
}
}
}

Snake in C++ won't turn twice in a row

I've just recently started to learn C++. I decided to program a little Snake game that runs in the console. It is relatively simple and doesn't look amazing, but it does it's thing as it's supposed to.The only issue I am having, is that my Snake won't turn twice in a row. In other words you can't do tight U-turns with it. It will however turn immediately after pressing the button. (Unless you just turned that is).
My code is 120 lines long so here it is:
First my includes and namespace:
#include <iostream>
#include <vector>
#include <conio.h>
#include <windows.h>
#include <random>
using namespace std;
This function draws the whole field in the console:
void drawGrid(vector<vector<char>> &g, int height, int width, int score, int time)
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), { 0,0 });
for (int r = 0; r < height; r++)
{
for (int c = 0; c < width; c++) std::cout << g[c][r] << " ";
std::cout << '|' << endl;
}
std::cout << "Current score: " << score << " ";
std::cout << "\nCurrent speed: " << time << " ";
}
This function checks whether the food is under the snake:
bool foodSnake(vector<int> &f, vector<vector<int>> &t, int l)
{
for (int i = 0; i < l; i++)
if (f[0] == t[i][0] && f[1] == t[i][1]) return true;
return false;
}
And this is the big poobah:
int main(void)
{
int sleeptime = 1000; // how long the break is between each frame
bool foodExists = 0;
int width = 20; //width and height of the field
int height = 15;
mt19937_64 engine; //random distributions for food generation
uniform_int_distribution<int> heightDist(0, height - 1);
uniform_int_distribution<int> widthDist(0, width - 1);
int tailLengthstart = 4;
int tailLength = tailLengthstart;
char movementDirection = 'u'; //starts moving upwards
char input;
bool alive = 1; //keeps the program running on death = 0
vector<int> pos = { (width - 1) / 2,(height - 1) / 2 }; //starts in the middle of field
vector<int> foodPos = pos; // so that the food generates at the beginning
vector<vector<int>> tail(tailLength, pos);
vector<vector<char>> emptyGrid(width, vector<char>(height, ' '));
vector<vector<char>> grid = emptyGrid;
while (alive) //runs main program until alive == 0
{
grid = emptyGrid; // clear grid
grid[pos[0]][pos[1]] = 'Q'; //place head in grid
if (!foodExists) //generates food if it was eaten
{
while (foodSnake(foodPos, tail, tailLength) || foodPos == pos)
{ // keeps regenerating until it isn't under the snake
foodPos[0] = widthDist(engine);
foodPos[1] = heightDist(engine);
}
foodExists = 1;
}
grid[foodPos[0]][foodPos[1]] = 'X'; //place food in grid
for (int i = 0; i < tailLength; i++) grid[tail[i][0]][tail[i][1]] = 'O'; // place tail in grid
drawGrid(grid, height, width, tailLength - tailLengthstart, sleeptime); //call above function to draw the grid
input = '_';
Sleep(sleeptime);
if (_kbhit()) { //this was the best way I found to wait for input
input = _getch();
switch (input)
{ //disallows moving in opposite direction otherwise changes direction
case 'w':
if (movementDirection == 'd') break;
movementDirection = 'u';
break;
case 'a':
if (movementDirection == 'r') break;
movementDirection = 'l';
break;
case 's':
if (movementDirection == 'u') break;
movementDirection = 'd';
break;
case 'd':
if (movementDirection == 'l') break;
movementDirection = 'r';
break;
case '_':
break;
}
}
for (int i = tailLength - 1; i > 0; i--)
tail[i] = tail[i - 1];
tail[0] = pos; //move the tail along
if (movementDirection == 'u') pos[1]--;
if (movementDirection == 'l') pos[0]--;
if (movementDirection == 'r') pos[0]++;
if (movementDirection == 'd') pos[1]++; // move the head
if (pos[0] < 0 || pos[0] > width - 1 || pos[1] < 0 || pos[1] > height - 1)
alive = 0; // if head is out of bounds -> dead
for (int i = 0; i < tailLength; i++)
if (pos == tail[i])
alive = 0; // if head is on tail -> dead
if (foodPos == pos)
{ // if head is on food -> eat
foodExists = 0; // food needs to be generated
tail.push_back(tail[tailLength - 1]); //tail adds a link
tailLength++; // tail is now longer
if (tailLength % 5 == 0) sleeptime *= 0.75; // at certain lengths game speeds up
}
}
this next part happens once you are dead or alive == 0
std::system("cls");
std::cout << endl << endl << endl << endl << "\tYou have died" << endl << endl << endl << endl;
std::cout << endl;
std::system("pause");
return 0;
}
So if anyone has an idea why it's not turning quickly, please help. Or any other improvement ideas are welcome as well.
The problem with movement is caused by fact that you advance tail and changing direction causes head advance immediately. That means that there is always a step before snake would actually turn.
The state set as I see it:
Setup scene.
Check key.
Change direction of movement if key pressed and it isn't opposite of current direction.
Make old head tail and add a head element in set direction from old head.
Check for death
Check for food.
If food found, grow tail by changing TailLength.
If snake length is greater than TailLength, remove tail elements until they are equal.
Render scene
Sleep and go to 2.
It is better to represent snake by a list, not by a vector. It won't reallocate memory on size change or if you will cut first elements out.
If your platform is Windows (obviously, you're using Sleep() function instead of usleep), the answer to this question offers better solution for key detection.
Get key press in windows console
Similar solutions exist for POSIX platforms.
There is a little problem that you're waiting sleeptime even the key was pressed
Sleep(sleeptime);
The main cycle may be like this pseudo code
while (IsAlive())
{
currtime = 0;
DrawState();
while (currtime++ < sleeptime)
{
if (CheckAndProcessKeyboardInput())
break;
SleepOneMilliSecond();
}
}

C++ user input twice before specified response

I am making a whack-a-mole game for my class but I am stuck on the basic controls. I setup a basic board, using an array with a border using ascii symbols, with O representing the holes and X the hammer. When I go to move the hammer, lets say to the right, I have to press it twice for the hammer to move and I don't know why. It has to go through the whole loop 2 times before moving the hammer the right way.
#include <iostream>
#include <windows.h>
using namespace std;
bool gamerunning = true;
const int num = 20; //width
const int num2 = 40; //height
int x, y, score, perx, pery;
int hole1x, hole1y;
int hole2x, hole2y;
int hole3x, hole3y;
int hole4x, hole4y;
void setup(){
x= 5;
y=5;
hole1x = 15;
hole1y = 5;
hole2x = 15;
hole2y = 10;
hole3x = 25;
hole3y = 5;
hole4x = 25;
hole4y = 10;
score = 0;
perx = 15;
pery = 6;
}
//creating board
void draw(){
system("cls");
int i,j;
char Layout[num][num2];
for (i=0;i<num;i++){
for (j=0;j<num2;j++){
//boarder for play area
if (i==0 && j==0) //Top Left
Layout [i][j] = 201;
else if( i==0 && j==num2-1) //top right
Layout [i][j] = 187;
else if(i==num-1 && j==0) //bottom left
Layout [i][j] = 200;
else if(i ==num-1 && j==num2-1) //bottom right
Layout [i][j] = 188;
else if (i==0 || i==num - 1)
Layout[i][j]=205;
else if(j==0 || j==num2-1)
Layout [i][j] = 186;
else
Layout[i][j]=' ';
//holes
if(i == hole1y && j == hole1x)
Layout[i][j]= 'O';
if(i == hole2y && j == hole2x)
Layout[i][j]= 'O';
if(i == hole3y && j == hole3x)
Layout[i][j]= 'O';
if(i == hole4y && j == hole4x)
Layout[i][j]= 'O';
//character
if(i == pery && j == perx)
Layout[i][j]= 'X';
cout << Layout[i][j];
}
cout << endl;
}
}
void input(){
if(GetAsyncKeyState(VK_RIGHT)){
if(perx<=15)
perx +=10;
}
if(GetAsyncKeyState(VK_LEFT)){
if(perx>=25)
perx -=10;
}
if(GetAsyncKeyState(VK_DOWN)){
if(pery<=10)
pery +=5;
}
if(GetAsyncKeyState(VK_UP)){
if(pery>=10)
pery -=5;
}
if(GetAsyncKeyState(VK_ESCAPE)){
gamerunning = false;
}
}
void logic(){
}
int main(){
setup();
while(gamerunning == true){
draw();
input();
logic();
system("pause>nul");
}
system("cls");
cout << "GAME OVER" << endl;
return 0;
}
Here :
while(gamerunning == true)
{
draw();
input();
system("pause>nul");
logic();
}
You first draw your game board then you get the input, drawing will not happen until the next time loop execution, so your drawing will not update.
You need to put first draw call outside the loop (for initial drawing) then inside the loop call draw after input. like this :
draw();
while(gamerunning == true)
{
input();
draw();
system("pause>nul");
logic();
}