I'm making a game in class, and haven't yet gotten to using a game engine. But it's Tetris, and I'm having trouble for the first time in the class probably because I'm not exactly sure how everything works in C++ yet.
It was working well before my C++ class. And I took some of the professors' advice. The advice that I believe is the problem is I removed the usage of #include "class.cpp"
and started to use #include "class.h"
in src.cpp
, class being the name of that particular class.
If you're wondering about how I'm compiling this, it's through Visual Studio 2013 Community edition's compiler. Using the cl command from vsvarsall.bat
(If you're following handmade hero you already know this). shell.bat
does the compiling and run.bat just runs the .exe that is created from shell.bat
.
I get this error: "
src.obj src.obj : error LNK2019: unresolved external symbol "public: __cdecl tetrimino::tetrimino(int)" (??0tetrimino@@QEAA@H@Z) referenced in function main
src.obj : error LNK2019: unresolved external symbol "public: __cdecl well::well(void)" (??0well@@QEAA@XZ) referenced in function main
src.obj : error LNK2019: unresolved external symbol "public: void __cdecl well::AddPieceToWell(class tetrimino)" (?AddPieceToWell@well@@QEAAXVtetrimino@@@Z) referenced in function main
src.obj : error LNK2019: unresolved external symbol "public: void __cdecl well::DataDump(int)" (?DataDump@well@@QEAAXH@Z) referenced in function main
src.exe : fatal error LNK1120: 4 unresolved externals "
I'm guessing it's that the program doesn't know where the cpp is? I'm not including the class' cpp anywhere else in the code since my proc said to only do .h's
I've looked through other similar questions on stack overflow and the answers seem complex and not exactly , and some had to do with messing with visual studio, but I'm using Atom and not a solution in visual studio. Though if there is a post somewhere I'll try and understand it if someone links it.
SOURCE: src.cpp
/*
Author: Jesse Coyle
Program: Wells Glazes!
Description: Inheritence and Classes extended
Date: 2/2/2015
*/
#include <iostream>
#include <iomanip>
#include <ctime>
#include <random>
using namespace std;
#include "well.h"
#include "tetrimino.h"
int main()
{
well WellsGlazes;
tetrimino TetriminoTestObject;
WellsGlazes.AddPieceToWell(TetriminoTestObject);
//WellsGlazes.ClearFullRows();
WellsGlazes.DataDump(1);
//system("pause");
return 0;
}
tetrimino.cpp:
/*
Author: Jesse Coyle
Description: Tetrimino class methods
Date: 1/26/2015
*/
tetrimino::tetrimino(int Type)
{
static int TimeChanger = 0;
srand(time(NULL) + TimeChanger++);
int ARandomInt = rand() % Type;
SetPosition(0, 0);
switch(ARandomInt)
{
case 0:
{
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{0, 0, 0, 0},
{1, 1, 1, 1},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 't';
}
break;
case 1:
{
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{1, 0, 0, 0},
{1, 1, 1, 0},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 'b';
}
break;
case 2:
{
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{1, 1, 1, 0},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 'o';
}
break;
case 3:
{
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 0},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 'y';
}
break;
case 4:
{
// NOTE(Jesse): Does square move when rotated?
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{0, 1, 1, 0},
{1, 1, 0, 0},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 'g';
}
break;
case 5:
{
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{0, 0, 1, 0},
{1, 1, 1, 0},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 'p';
}
break;
case 6:
{
int BufferGrid[4][4] =
{
{0, 0, 0, 0},
{0, 1, 0, 0},
{1, 1, 1, 0},
{0, 0, 0, 0}
};
CopyArray(BufferGrid, Grid);
Color = 'r';
}
break;
}
}
void
tetrimino::CopyArray(int const Array[][4], int ArrayCopy[][4])
{
for (int Y = 0;
Y < 4;
++Y)
{
for (int X = 0;
X < 4;
++X)
{
ArrayCopy[Y][X] = Array[Y][X];
}
}
}
void const
tetrimino::PrintArray(int Array[][4])
{
for (int Y = 0;
Y < 4;
++Y)
{
for (int X = 0;
X < 4;
++X)
{
cout << Array[Y][X];
}
cout << endl;
}
}
char
tetrimino::GetColor(void)
{
return Color;
}
position
tetrimino::GetPosition(void)
{
return Pos;
}
void
tetrimino::GetGrid(int Grid[][4])
{
for (int X = 0;
X < 4;
++X)
{
for (int Y = 0;
Y < 4;
++Y)
{
Grid[X][Y] = this->Grid[X][Y];
}
}
}
void
tetrimino::SetPosition(position NewPos)
{
Pos.X = NewPos.X;
Pos.Y = NewPos.Y;
}
void
tetrimino::SetPosition(int X, int Y)
{
Pos.X = X;
Pos.Y = Y;
}
void
tetrimino::RotateClockwise(void)
{
int ArrayBuffer[4][4];
//To Mirror the rotated shape correctly
int Reverse = 3;
//Rotate and mirror(since rotating mirrors the shape)
for (int X = 0;
X < 4;
++X)
{
for(int Y = 0;
Y < 4;
++Y)
{
ArrayBuffer[Y][Reverse] = Grid[X][Y];
}
--Reverse;
}
for(int X = 0;
X < 4;
++X)
{
for(int Y = 0;
Y < 4;
++Y)
{
Grid[X][Y] = ArrayBuffer[X][Y];
}
}
}
void
tetrimino::RotateCounterClockwise(void)
{
int ArrayBuffer[4][4];
//To mirror the rotation/rotate correctly
int Reverse;
//Rotate the shape
for(int X = 0;
X < 4;
++X)
{
Reverse = 3;
for(int Y = 0;
Y < 4;
++Y)
{
ArrayBuffer[Reverse][X] = Grid[X][Y];
--Reverse;
}
}
for(int X = 0;
X < 4;
++X)
{
for(int Y = 0;
Y < 4;
++Y)
{
Grid[X][Y] = ArrayBuffer[X][Y];
}
}
}
// NOTE(Jesse):
void
tetrimino::MoveLeft(void)
{
--Pos.X;
}
void
tetrimino::MoveRight(void)
{
++Pos.X;
}
void
tetrimino::MoveDown(void)
{
++Pos.Y;
}
void
tetrimino::MoveUp(void)
{
--Pos.Y;
}
tetrimino.h:
/*
Author: Jesse Coyle
Description: Tetrimino class header file
Date: 1/28/2015
*/
#ifndef TETRIMINO_H
struct position
{
int X;
int Y;
};
class tetrimino
{
private:
int Grid[4][4]; //contains only zeros and ones
char Color;
position Pos;
public:
// constructor
tetrimino(int Type = 7); // valid type values are 0-6
char GetColor(void);
position GetPosition(void);
void GetGrid(int Grid[][4]);
void CopyArray(int const Array[][4], int ArrayCopy[][4]);
void PrintArray(int Array[][4]);
void SetPosition(position NewPos);
void SetPosition(int X, int Y);
void RotateClockwise(void);
void RotateCounterClockwise(void);
void MoveLeft(void);
void MoveRight(void);
void MoveDown(void);
void MoveUp(void);
};
#define TETRIMINO_H
#endif
well.cpp:
well::well(void)
{
Width = 8;
Height = 24;
FillArray(Grid, '.');
/*
int BufferGrid[24][8] =
{
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
}
CopyGrid(BufferGrid, Grid);
*/
}
void
well::CopyArray(char const Array[][8], char ArrayCopy[][8])
{
for (int Y = 23; Y > 0; --Y)
{
for (int X = 0; X < 8; ++X)
{
ArrayCopy[Y][X] = Array[Y][X];
}
}
}
void const
well::PrintArray(char Array[][8], int Width)
{
for (int Y = 23; Y >= 0; --Y)
{
for (int X = 0; X < 8; ++X)
{
cout << setw(Width) << Array[Y][X];
}
cout << endl;
}
}
void
well::FillArray(char Array[][8], char Character)
{
for (int Y = 23; Y >= 0; --Y)
{
for (int X = 0; X < 8; ++X)
{
Array[Y][X] = Character;
}
}
}
// TODO(Jesse): Fix possible spawning in another tetrimino
// NOTE(Jesse): Could be optimized through caches, though don't bother...
// Although might be a good idea at some point. Depending on how I want to
// Do game update rates
bool
well::DoesPieceFit(tetrimino Object)
{
// NOTE(Jesse): I'm going to overcomplicate this...
int ObjectGrid[4][4];
Object.GetGrid(ObjectGrid);
int Left;
int Right;
int Top;
position Pos = Object.GetPosition();
bool FoundBarrier = false;
for(int X = 0; X < 4; ++X)
{
for(int Y = 0; Y < 4; ++Y)
{
if(ObjectGrid[Y][X] == 1)
{
Left = X;
FoundBarrier = true;
break;
}
}
if(FoundBarrier)
{
break;
}
}
FoundBarrier = false;
for(int X = 3; X >= 0; --X)
{
for(int Y = 0; Y < 4; ++Y)
{
if(ObjectGrid[Y][X] == 1)
{
Right = X;
FoundBarrier = true;
break;
}
}
if(FoundBarrier)
{
break;
}
}
FoundBarrier = false;
for(int Y = 0; Y < 4; ++Y)
{
for(int X = 0; X < 4; ++X)
{
if(ObjectGrid[Y][X] == 1)
{
Top = X;
FoundBarrier = true;
break;
}
}
if(FoundBarrier)
{
break;
}
}
if(Pos.X + Left >= 0 &&
Pos.X + Right <= 7 &&
Pos.Y - Top >= 0)
{
return true;
}
return false;
}
void
well::AddPieceToWell(tetrimino Object)
{
position PiecePos;
//Integrate into well
PiecePos = Object.GetPosition();
int PieceGrid[4][4];
Object.GetGrid(PieceGrid);
PrintArray(PieceGrid);
cout << Object.GetColor();
cout << "(" << PiecePos.X << ", " << PiecePos.Y << ")" << endl;
//Y is different to compensate for mysterious Y offset (Note): May be just from displaying?
for(int YOffset = 0; YOffset < 4; ++YOffset)
{
for(int XOffset = 0; XOffset < 4; ++XOffset)
{
if(PieceGrid[YOffset][XOffset] == 1)
{
Grid[PiecePos.Y + YOffset][PiecePos.X + XOffset] = Object.GetColor();
}
}
}
}
bool
well::IsRowFull(int Y)
{
for(int X = 0;
X < 8;
++X)
{
if(Grid[Y][X] == '.')
{
return false;
}
}
return true;
}
void
well::ClearRow(int Y)
{
for(int X = 0; X < 8; ++X)
{
Grid[Y][X] = '.';
}
}
//Call Every Frame?
int
well::ClearFullRows(void)
{
static int Score = 0;
bool HadCleared = false;
for(int Y = 0; Y < 24; ++Y)
{
if(IsRowFull(Y))
{
ClearRow(Y);
Score += 100;
HadCleared = true;
}
}
bool LineCascaded = false;
for(int Y = 0; Y < 23; ++Y)
{
for(int X = 0; X < 8; ++X)
{
if(Grid[Y][X] != '.' && Grid[Y+1][X] == '.')
{
char Buffer1 = Grid[Y][X];
char Buffer2 = Grid[Y+1][X];
Grid[Y+1][X] = Buffer1;
Grid[Y][X] = '.';
LineCascaded = true;
}
//Trying to fix weird missing dots for empty spots.
if(Grid[Y][X] == ' ')
{
Grid[Y][X] = '.';
}
}
if(LineCascaded)
{
Y = 0;
LineCascaded = false;
}
}
// NOTE(Jesse): This isn't working out...
/*
//CascadeRows Down
if(HadCleared)
{
bool ClearTop = true;
bool ClearBottom = true;
int MemoryY = 0;
// NOTE(Jesse): Like Bubblesort But more of a weird cocktail sort kinda method.
while(!ClearTop && !ClearBottom)
{
bool WillBreak = false;
ClearTop = true;
ClearBottom = true;
for(int Y = MemoryY; Y < GetHeight(); ++Y)
{
for(int X = 0; X < GetWidth(); ++X)
{
if(Grid[Y][X] != ' ' && Grid[Y+1][X] == ' ')
{
Grid[Y+1][X] == Grid[Y][X];
Grid[Y][X] = ' ';
ClearBottom = false;
MemoryY = Y;
WillBreak = true;
}
}
if(WillBreak)
{
WillBreak = false;
break;
}
}
for(int Y = MemoryY; Y >= 0; --Y)
{
for(int X = 0; X < GetWidth(); ++X)
{
if(Grid[Y][X] != ' ' && Grid[Y-1][X] == ' ')
{
Grid[Y-1][X] = Grid[Y][X];
Grid[Y][X] = ' ';
ClearTop = false;
MemoryY = Y;
WillBreak = true;
}
}
if(WillBreak)
{
WillBreak = false;
break;
}
}
}
}
*/
return Score;
}
//Best to be tested later
bool
well::TopExeeded(void)
{
return false;
}
// NOTE(Jesse): May never use this, I may just use copy array. [it just calls copy array anyway]
void
well::GetGrid(char AGrid[][8])
{
CopyArray(Grid, AGrid);
}
void
well::PrintWell(int Width)
{
// TODO(Jesse): This is printing out some weird stuff... Possibly a linker error?
// NOTE(Jesse): Problem was that the conditional didn't like the GetWidth and GetHeight statements.
for(int Y = 0;
Y < 24;
++Y)
{
for(int X = 0;
X < 8;
++X)
{
cout << setw(Width) << Grid[Y][X];
}
cout << endl;
}
}
// NOTE(Jesse): Testing Purposes for class methods
void
well::DataDump(int Width)
{
PrintWell(Width);
}
well.h:
#ifndef WELL_H
#include "tetrimino.h"
class well
{
private:
char Grid[24][8];
int Width;
int Height;
public:
well(void);
bool DoesPieceFit(tetrimino Object);
bool TopExeeded(void);
bool IsRowFull(int Row);
int ClearFullRows(void);
void CascadeRows(void);
void PrintArray(char Array[][8], int Width);
void CopyArray(char const Array[][8], char ArrayCopy[][8]);
void FillArray(char Array[][8], char Character);
void ClearRow(int Row);
void GetGrid(char Grid[][8]);
void AddPieceToWell(tetrimino Object);
void PrintWell(int Width);
void DataDump(int Width);
};
#define WELL_H
#endif
I apologize in advance because of other errors that could come up, but I think I can fix those after this weird linker error.
And this is how I build my file. Just as in handmade hero:
@ECHO OFF
DEL build\*.* /q /s
IF NOT EXIST "build" mkdir "build"
set CommonCompilerFlags = -Z7
set CommonLinkerFlags = -incremental:no -opt:ref
REM 32-bit build
REM cl %CommonCompilerFlags% ..\code\src.cpp /link -subsystem:windows,5.1 %CommonLinkerFlags%
REM 64-bit build
CALL "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64
REM Optimization switches /O2
CD build
cl %CommonCompilerFlags% ..\code\tetrimino.cpp /link %CommonLinkerFlags%
cl %CommonCompilerFlags% ..\code\well.cpp /link %CommonLinkerFlags%
cl %CommonCompilerFlags% ..\code\src.cpp /link %CommonLinkerFlags%