Creating a thread inside the class in C++ - c++

I am a beginner in threading with C++. Tried to create a thread t1 inside the class, but I want it not to be initialized. For this I did:
In the class variable, thread *t1 as if were to declare the class variable without initializing it.
Then from the constructor, I did:
t1 = new Thread(functionName);
But, there's some error that I didn't get. I previously had simple working experience with threading in Java.
Will this strategy cause an interlocking problem, assuming the solution exists to the way I want to implement it. (if I want to access the same variable without modifying it). Code goes like this:
class game:protected gameObjects
{
thread *t1;
///-------------------- Variables-------------------///
char keyPressed = NULL;
/// structure for holding player information.
struct player
{
int x, y0, y1,color;
};
player player1, player2;
/// for ball
int ballX, ballY, ballColor, ballBorderColor;
///--------------------------------------------------///
void initializeData()
{
ballX = 42;
ballY = 130;
player1.color = LIGHTCYAN;
player1.x = 30;
player1.y0 = 100;
player1.y1 = 200;
player2.color = LIGHTMAGENTA;
player2.x = 600;
player2.y0 = 100;
player2.y1 = 200;
/// Basic setUp For Game and Game Screen
ballBorderColor = RED;
ballColor = GREEN;
}
void updateScoreBoard()
{
/// whole score board border.
drawRect(20,10,620,50,RED);
/// left score board
drawRect(21,11,321,49,CYAN);
setfillstyle(SOLID_FILL,CYAN);
floodfill(30,40,CYAN);
setbkcolor(CYAN);
setcolor(LIGHTGREEN);
outtextxy(35,20,"Score:0");
///right score board.
drawRect(323,11,619,49,LIGHTMAGENTA);
setfillstyle(SOLID_FILL,LIGHTMAGENTA);
floodfill(330,40,LIGHTMAGENTA);
setbkcolor(LIGHTMAGENTA);
setcolor(LIGHTGREEN);
outtextxy(350,20,"Score:1");
}
void ballPosition()
{
setfillstyle(SOLID_FILL,ballColor);
drawCircle(ballX,ballY,10,ballBorderColor); ///ball for game
floodfill(ballX,ballY,ballBorderColor);
}
void playerBatPosition()
{
drawLine(player1.x,player1.y0,player1.x,player1.y1,player1.color);
drawLine(player2.x,player2.y0,player2.x,player2.y1,player2.color);
}
void setBackground()
{
setfillstyle(SOLID_FILL,background);
drawRect(0,0,getmaxx(),getmaxy(),RED);
floodfill(getmaxx()/2,getmaxy()/2,RED);
drawRect(20,60,620,470,WHITE); ///white line.
}
void updateScreenActivity()
{
playerBatPosition();
}
void startPlaying()
{
do
{
keyPressed = _getch();
if(keyPressed == 'w')
{
if(player1.y0 > 60)
{
drawLine(player1.x,player1.y0,player1.x,player1.y1,background);
player1.y0-=5;
player1.y1-=5;
}
}
else if(keyPressed == 's')
{
if(player1.y1 < 470)
{
drawLine(player1.x,player1.y0,player1.x,player1.y1,background);
player1.y0+=5;
player1.y1+=5;
}
}
if(keyPressed == 't')
{
if(player2.y0 > 60)
{
drawLine(player2.x,player2.y0,player2.x,player2.y1,background);
player2.y0-=5;
player2.y1-=5;
}
}
else if(keyPressed == 'g')
{
if(player2.y1 < 470)
{
drawLine(player2.x,player2.y0,player2.x,player2.y1,background);
player2.y0+=5;
player2.y1+=5;
}
}
updateScreenActivity();
}
while(keyPressed != 'q');
}
///-------------------Threading call --------------///
void startBallMovement(){
cout<<"Hello world"<<endl;
}
///-----------------------------------------------///
public:
game()
{
cleardevice();
initializeData();
setBackground();
updateScoreBoard();
playerBatPosition();
ballPosition();
startPlaying();
t1 = new thread(startBallMovement);
}
};
What I want to do is create a movement of a circle in different paths from the thread. I might sometimes need to access the variables from the thread to simulate the movement in different directions as per the user's strategy.
Error:

Your class implementation looks a bit lousy. But try something like this.
class game
{
private: thread* t;
public:
game()
{
t = new thread([this]() {startBallMovement();} );
}
~game()
{
if(t != nullptr)
{
t->join();
delete t;
}
}
void startBallMovement()
{
}
};

Related

How to reference a classes attribute inside another class method?

I'm trying to create a little ascii game where I can run around kill enemies etc. However I'm new to C++ and I would like to do something if the players location is at a certain point.
Below is a simpler version of the code and a picture of the problem:
#include <iostream>
using namespace std;
struct Game
{
bool bGameOver = false;
int iWidth = 20;
int iHeight = 40;
void Draw() {
if (player.x == 5)
{
cout << "Hello"
}
}
};
struct Player
{
bool bGameOver = false;
int x = 0;
int y = 0;
};
void Setup()
{
}
int main()
{
Game game;
Player player;
while (!game.bGameOver)
{
Setup();
}
}
Picture of the error
The variable player is local in function main, so it's not visible where you tried to use it in Game::Draw.
One solution could be to make player a global variable. You'll need to switch the order of the structs:
struct Player
{
bool bGameOver = false;
int x = 0;
int y = 0;
};
Player player;
struct Game
{
bool bGameOver = false;
int iWidth = 20;
int iHeight = 40;
void Draw() {
if (player.x == 5)
{
cout << "Hello"
}
}
};
But I'd prefer to instead model things so a Game "has a" Player. So make Player a member of the Game:
struct Player
{
bool bGameOver = false;
int x = 0;
int y = 0;
};
struct Game
{
Player player;
bool bGameOver = false;
int iWidth = 20;
int iHeight = 40;
void Draw() {
if (player.x == 5)
{
cout << "Hello"
}
}
};
(Aside: You probably don't want two different values called bGameOver, since keeping them in sync would be extra work. It sounds more like a game property than a player property to me.)

Exception thrown: read access violation. it was 0xFFFFFFFFFFFFFFFF

I'm trying to write the Space Invaders clone for Windows console, and it felt like everything was going fine, but here comes this crash. The program compiles without errors, however instantly crashes on start up.
I admit that I don't know pointers very well, and I believe that the problem is somewhere there.
#include "stdafx.h"
#include <vector>
#include <random>
#include <chrono>
#include <thread>
#include <memory>
#include <SDKDDKVer.h>
#include "Vector2D.h"
#include "Renderer.h"
std::default_random_engine rGen;
typedef std::uniform_int_distribution<int> intRand;
typedef std::uniform_real_distribution<float> floatRand;
char ObjectType[][64] =
{
"ot_AlienShip",
"ot_PlayerShip",
"ot_AlienLaser",
"ot_PlayerLaser",
"ot_Explosion"
};
class PlayField;
class GameObject
{
public:
char* m_objType = nullptr;
Vector2D pos;
unsigned char sprite;
virtual void Update(PlayField& world) {};
virtual bool DecreaseHealth() { return true; };
};
class Input
{
public:
virtual bool Left() = 0;
virtual bool Right() = 0;
virtual bool Fire() = 0;
};
class RndInput : public Input
{
public:
virtual bool Left() override { floatRand keyRate(0, 1); return (keyRate(rGen) < 0.3f); }
virtual bool Right() override { floatRand keyRate(0, 1); return (keyRate(rGen) < 0.4f); };
virtual bool Fire() override { floatRand keyRate(0, 1); return (keyRate(rGen) < 0.5f); };
};
class PlayField
{
private:
typedef GameObject* GameObjPtr;
std::vector<GameObjPtr> gameObjects;
public:
Input* cotrollerInput = nullptr;
GameObject* it = new GameObject;
//it = new GameObject;
Vector2D bounds;
// Number of available active laser slots for aliens and player
int AlienLasers = 10;
int PlayerLasers = 4;
explicit PlayField(Vector2D iBounds) : bounds(iBounds) {};
const std::vector<GameObjPtr>& GameObjects() { return gameObjects; }
void Update()
{
// update list of active objects in the world
for (auto it : gameObjects)
{
it->Update(*this); //The crash is here "Unhandled exception thrown: read access violation. it was 0xFFFFFFFFFFFFFFFF."
}
}
GameObject* GetPlayerObject()
{
auto it = std::find_if(gameObjects.begin(), gameObjects.end(), [](GameObjPtr in) { return (strcmp(in->m_objType,"ot_PlayerShip")==0); });
if (it != gameObjects.end())
return (*it);
else
return nullptr;
}
void SpawnLaser(GameObject* newObj)
{
if (strcmp(newObj->m_objType, "ot_AlienLaser")==0)
AlienLasers--;
else if (strcmp(newObj->m_objType, "ot_PlayerLaser")==0)
PlayerLasers--;
AddObject(newObj);
}
void DespawnLaser(GameObject* newObj)
{
if (strcmp(newObj->m_objType, "ot_AlienLaser")==0)
AlienLasers++;
else if (strcmp(newObj->m_objType, "ot_PlayerLaser")==0)
PlayerLasers++;
RemoveObject(newObj);
}
void AddObject(GameObject* newObj)
{
//gameObjectsToAdd.push_back(GameObjPtr(newObj));
gameObjects.push_back(newObj);
}
void RemoveObject(GameObject* newObj)
{
//gameObjectsToRemove.push_back(newObj);
auto it = std::find_if(gameObjects.begin(), gameObjects.end(), [&](GameObjPtr in) { return (in==newObj); });
gameObjects.erase(it);
}
};
class Explosion : public GameObject
{
public:
// Explosion lasts 5 ticks before it dissappears
int timer = 5;
Explosion() { m_objType = new char[64]; strcpy(m_objType, "ot_Explosion"); sprite = RS_Explosion; }
~Explosion() { delete[] m_objType; }
void Update(PlayField& world) override
{
timer--;
if (!timer)
{
world.RemoveObject(this);
delete this;
}
}
};
class AlienLaser : public GameObject
{
public:
AlienLaser() { m_objType = new char[64]; strcpy(m_objType, "ot_AlienLaser"); sprite = RS_AlienLaser; }
~AlienLaser() { delete[] m_objType; }
void Update(PlayField& world) override
{
bool deleted = false;
pos.y += 1.f;
if (pos.y > world.bounds.y)
{
deleted = true;
}
GameObject* player = world.GetPlayerObject();
if (player && pos.IntCmp(player->pos))
{
deleted = true;
//Spawn explosion, kill player
GameObject& no = *(new Explosion);
no.pos = pos;
world.AddObject(&no);
world.RemoveObject(player);
}
if (deleted)
{
world.DespawnLaser((GameObject*)this);
delete this;
}
}
};
class PlayerLaser : public GameObject
{
public:
PlayerLaser() { m_objType = new char[64]; strcpy(m_objType, "ot_PlayerLaser"); sprite = RS_PlayerLaser; }
~PlayerLaser() { delete[] m_objType; }
void Update(PlayField& world) override
{
bool deleted = false;
pos.y -= 1.f;
if (pos.y < 0)
{
deleted = true;
}
for (auto it : world.GameObjects())
{
if (strcmp(it->m_objType,"ot_AlienShip")==0 && it->pos.IntCmp(pos))
{
deleted = true;
//Spawn explosion, kill the alien that we hit
GameObject& no = *(new Explosion);
no.pos = pos;
world.AddObject(&no);
if (it->DecreaseHealth())
world.RemoveObject(it);
}
}
if (deleted)
{
world.DespawnLaser(this);
delete this;
}
}
};
class Alien : public GameObject
{
public:
Alien() { m_objType = new char[64]; strcpy(m_objType, "ot_AlienShip"); sprite = RS_Alien; }
~Alien() { delete m_objType; }
private:
const float maxUpdateRate = 0.01f;
const float transformEnergy = 1.f;
enum AlienState
{
as_Normal,
as_Better
};
// Variables dictating energy level for upgrade, direction of movement, and current speed
float health = 1.f;
float energy = 0.f;
float direction = 1.f;
float velocity = 0.5f;
AlienState state{};
void Transform()
{
state = as_Better;
sprite = RS_BetterAlien;
velocity *= 2.f;
}
bool DecreaseHealth() override { health -= 1.f; return health <= 0; }
void Update(PlayField& world) override
{
pos.x += direction * velocity;
// Border check
if (pos.x < 0 || pos.x >= world.bounds.x - 1)
{
direction = -direction;
pos.y += 1;
}
// Border check vertical:
if (pos.y >= world.bounds.y - 1)
{
// kill player
GameObject* player = world.GetPlayerObject();
if (player && pos.IntCmp(player->pos))
{
//Spawn explosion
GameObject& no = *(new Explosion);
no.pos = pos;
world.AddObject(&no);
world.RemoveObject(player);
}
}
// Transform into better Alien
if (state!=as_Better)
{
floatRand updateRate(-maxUpdateRate, 2*maxUpdateRate);
energy += updateRate(rGen);
if (energy >= transformEnergy)
Transform();
}
floatRand fireRate(0, 1);
if (fireRate(rGen) < 0.5 && world.AlienLasers>0)
{
//Spawn laser
GameObject& newLaser = *(new AlienLaser);
newLaser.pos = pos;
world.SpawnLaser(&newLaser);
}
}
};
class PlayerShip : public GameObject
{
public:
PlayerShip() { m_objType = new char[64]; strcpy(m_objType, "ot_PlayerShip"); sprite = RS_Player; }
~PlayerShip() { delete m_objType; }
void Update(PlayField& world) override
{
if (world.cotrollerInput->Left())
pos.x -= 1;
else if (world.cotrollerInput->Right())
pos.x += 1;
if (world.cotrollerInput->Fire() && world.PlayerLasers>0)
{
//Spawn laser
GameObject& newLaser = *(new PlayerLaser);
newLaser.pos = pos;
world.SpawnLaser(&newLaser);
}
}
};
int main()
{
rGen.seed(1);
Vector2D size(80, 28);
Renderer mainRenderer(size);
PlayField world(size);
intRand xCoord(0, (int)size.x-1);
intRand yCoord(0, 10);
// Populate aliens
for (int k = 0; k < 20; k++)
{
Alien& a = *(new Alien);
a.pos.x = (float)xCoord(rGen);
a.pos.y = (float)yCoord(rGen);
world.AddObject(&a);
}
// Add player
PlayerShip& p = *(new PlayerShip);
p.pos = Vector2D(40, 27);
world.AddObject(&p);
world.Update();
{
RenderItemList rl;
for (auto it : world.GameObjects())
{
RenderItem a = RenderItem(Vector2D(it->pos), it->sprite);
rl.push_back(a);
}
mainRenderer.Update(rl);
// Sleep a bit so updates don't run too fast
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return 0;
}
In addition, VS gives the following info:
I assume, that the pointer (or the object) appears to be cleared somewhere before, but I have no idea how to trace it. Thanks in advance.
The various ::Update methods you have add and remove objects from gameObjects while you are traversing it in Playfield::Update. This is a guaranteed crash as it invalidates the implicit iterator in your for loop.
To solve this, either:
Have GameObject::Update return a boolean that signifies if the object can be removed or not. This requires you to rewrite the loop in Playfield::Update with explicit iterators so you an do it = gameObjects.erase(it);. This will still not allow you to add new objects, though.
Defer additions and removals until the end of the game loop. Add a markForAddition / markForRemoval method that will remove these objects from the game world after Playfield::Update has gone through. You will need to do some extra bookkeeping to make sure you do not update or draw objects that have been removed earlier in the same loop, but that is surmountable.
Switch data structures: a std::list does not invalidate its iterators if you remove an object somewhere. You do still need to be careful with the current element though.

How to use classes inside another class function independently of where it is declared in C++?

I'm trying to create a Monopoly game in C++ and I've been messing with object-oriented-programming, the problem happens with the classes "Game" and "Player", I would like to know how to use "Game"'s functions inside "Player" and "Player"'s functions inside "Game", but I've been getting a compiler error saying that the class is not defined.
Switching class positions won't work (obviously) but I tried anyways.
Code (reduced and minimized to the Game and Player classes):
namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game {
private:
bool running = false;
int turn = 1;
int currentPlayerID;
int startingMoney = 1000;
std::vector<Player> players;
public:
// Functions
void createPlayer() {
++currentPlayerID;
Player newPlayer(currentPlayerID, startingMoney);
players.push_back(newPlayer);
++currentPlayerID;
}
void createPlayers(int playerAmount) {
for (int i = 0; i <= playerAmount; ++i) {
createPlayer();
}
}
Player getPlayer(int index) {
Player p = players[index];
return p;
}
};
class Player {
private:
int playerID;
int money;
std::vector<int> propertiesOwned;
void addProperty(int id) {
this->propertiesOwned.push_back(id);
}
public:
// Constructor
Player(int pID, int sMoney) {
this->playerID = pID;
this->money = sMoney;
}
// Functions
Player payMoney(int payAmount, unsigned int destinationID, Game engine) {
this->money -= payAmount;
if (destinationID > 0) {
// Checks if you're paying to a player or bank
bool playerFound = false;
for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
if (engine.getPlayer(i).getID() == destinationID) {
playerFound = true;
break;
}
}
if (playerFound) {
// Player was found
engine.getPlayer(destinationID).giveMoney(payAmount);
return;
}
else {
std::cout << "\nERROR: Invalid player ID at function payMoney\n";
return;
}
}
else {
// You're paying to the bank
}
return;
}
void buyProperty(int id, int price, Game engine) {
payMoney(price, 0, engine);
addProperty(id);
}
void giveMoney(int payMoney) {
this->money += payMoney;
}
// Returns
inline int getMoney() { return this->money; }
inline int getID() { return this->playerID; }
inline auto getProperties(int index) {
auto p = propertiesOwned[index];
return p;
}
inline int getPropertyAmount() {
int amount = std::size(propertiesOwned);
return amount;
}
};
}
I expected the classes to run the other classes function normally, but it seens like that in C++, classes are defined in certain order, and you can only access classes (in a class) declared before the class you're using, feedback and alternatives that fix this would help
You are correct that in C++ declaration order matters, and that is the cause of your errors, however there are a few other issues with the code.
Firstly, you should swap the order that Game and Player are defined. This will make it easier, as Player relies on Game fewer times than Game relies on Player.
Next, add a forward declaration for Game before the definition of Player:
class Game;
This tells the compiler that a class named Game exists and allows you to use it in scenarios where it doesn't need to know the contents (i.e. definition) of the class.
Next, make payMoney and buyProperty accept their engine parameter by reference instead of by value by changing the parameter specifier to Game &engine. This is important for two reasons. First, passing by value can only be done if you have already defined the type, which we have not (we've only declared it). Second, passing by value creates a copy of the object, which in this case means a completely new vector of completely new Player objects, and the changes will not synchronize back to the old object. See here for a better explanation of references.
Next, you need to extract the definition of payMoney to after the definition of Game. The reason is that while the parameter list of payMoney no longer relies on the definition of Game, the code in the function body does (because it calls functions on the engine object). See the end for what this looks like.
This fixes all the problems with declaration/definition order. You also should make payMoney return void as its return value is never provided and never used, pick a consistent type for IDs (either int or unsigned int, not a mix), and add the getPlayerAmount to Game.
Here's what the final code could look like:
namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game;
class Player {
private:
int playerID;
int money;
std::vector<int> propertiesOwned;
void addProperty(int id) {
this->propertiesOwned.push_back(id);
}
public:
// Constructor
Player(int pID, int sMoney) {
this->playerID = pID;
this->money = sMoney;
}
// Functions
void payMoney(int payAmount, int destinationID, Game &engine);
void buyProperty(int id, int price, Game &engine) {
payMoney(price, 0, engine);
addProperty(id);
}
void giveMoney(int payMoney) {
this->money += payMoney;
}
// Returns
inline int getMoney() { return this->money; }
inline int getID() { return this->playerID; }
inline auto getProperties(int index) {
auto p = propertiesOwned[index];
return p;
}
inline int getPropertyAmount() {
int amount = std::size(propertiesOwned);
return amount;
}
};
class Game {
private:
bool running = false;
int turn = 1;
int currentPlayerID;
int startingMoney = 1000;
std::vector<Player> players;
public:
// Functions
void createPlayer() {
++currentPlayerID;
Player newPlayer(currentPlayerID, startingMoney);
players.push_back(newPlayer);
++currentPlayerID;
}
void createPlayers(int playerAmount) {
for (int i = 0; i <= playerAmount; ++i) {
createPlayer();
}
}
Player getPlayer(int index) {
Player p = players[index];
return p;
}
int getPlayerAmount() {
int amount = players.size();
return amount;
}
};
void Player::payMoney(int payAmount, int destinationID, Game &engine) {
this->money -= payAmount;
if (destinationID > 0) {
// Checks if you're paying to a player or bank
bool playerFound = false;
for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
if (engine.getPlayer(i).getID() == destinationID) {
playerFound = true;
break;
}
}
if (playerFound) {
// Player was found
engine.getPlayer(destinationID).giveMoney(payAmount);
return;
}
else {
std::cout << "\nERROR: Invalid player ID at function payMoney\n";
return;
}
}
else {
// You're paying to the bank
}
return;
}
}
Side note: it's technically better C++ to use size_t instead of int for variables storing the size of vectors, as that is what the size functions return (and it's an unsigned integer type whereas int is signed), but that's not especially important.

Cant Detect if mouse button is held or just tapped once

Well i made a bunny that teleports on tap and i want to make it so if you hold for more than 0.3f a bubble activates and protects it i tried multiple code variates but i cant get it to work in some situation the bunny teleports and activates the bubble after and in others it doesnt i know its something simple and i just have to adjust the if / else if so i will be thankfull for eny help
using UnityEngine;
using System.Collections;
public class tap : MonoBehaviour {
// Use this for initialization
public GameObject Bunny;
public GameObject BunnyUpEffect;
public GameObject BunnyDownEffect;
public static bool IsHeld = false;
float TimeHeld = 0f;
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0)) {
TimeHeld += Time.deltaTime;
if (TimeHeld > 0.3f) {
BubbleScript.BubbleActive = true;
IsHeld = true;
}
}
else {
BubbleScript.BubbleActive = false;
IsHeld = false;
TimeHeld = 0f;
if (Input.GetMouseButtonDown(0) && IsHeld == false) {
if (BunnyScript.BunnyAlive == true) {
if (BunnyScript.RunBottom == true) {
if (Stats.Energy > 0) {
BunnyUpEffect.GetComponent<BunnyUpEffect> ().Up ();
}
} else if (BunnyScript.RunBottom == false) {
BunnyDownEffect.GetComponent<BunnyDownEffect> ().Down ();
}
Bunny.GetComponent<BunnyScript> ().ChangePos ();
}
}
}
}
}

Passing an array of objects into another class constructor (Arduino IDE)

I am trying to pass an array of objects into another array, I am using the Arduino IDE, so I don't think using Vectors is possible.
The code complies, however it does not do what I wanted it to. (To use the the method of the passed object)
class Menu_Manager
{
private:
int _currentPage;
Main_Menu *main_menus[];
public:
//Problem
Menu_Manager(Main_Menu *main[], int numberOfMenus)
{
for (int x = 0; x <= numberOfMenus; x++)
{
*main_menus[x] = *main[x];
}
_currentPage = 0;
}
void start()
{
main_menus[_currentPage]->start();
if (_currentPage >= main_menus[0]->getTotalPage())
{
_currentPage = 0;
}
else if (_currentPage < 0)
{
_currentPage = main_menus[0]->getTotalPage();
}
}
};
Main file:
Main_Menu timer(1, lcd);
Main_Menu setting(2, lcd);
Main_Menu *allMM[] = { &timer, &setting };
Menu_Manager manager(&allMM[2], 2);