我在课堂上制作游戏,还没有使用游戏引擎。但它是俄罗斯方块,而且我第一次在课堂上遇到麻烦可能是因为我还不确定C ++中的一切是如何工作的。
它在我的C ++课之前运作良好。我带了一些教授和#39;咨询。我认为问题的建议是我删除了#include "class.cpp"
的使用并开始在#include "class.h"
中使用src.cpp
,类是该特定类的名称。
如果您想知道我是如何编译它的,那么它是通过Visual Studio 2013社区版的编译器实现的。使用来自vsvarsall.bat
的cl命令(如果您正在关注手工制作的英雄,那么您已经知道了这一点)。 shell.bat
进行编译,run.bat只运行从shell.bat
创建的.exe。
我收到此错误:"
src.obj src.obj:错误LNK2019:未解析的外部符号" public: __cdecl tetrimino :: tetrimino(int)" (?? 0tetrimino @@ QEAA @ H @ Z)在函数main
中引用src.obj:错误LNK2019:未解析的外部符号" public:__ cdecl 井::井(无效)" (?? 0well @@ QEAA @ XZ)在函数main
中引用src.obj:错误LNK2019:未解析的外部符号" public:void __cdecl well :: AddPieceToWell(类tetrimino)" (?AddPieceToWell @ well @@ QEAAXVtetrimino @@@ Z)在函数中引用 主
src.obj:错误LNK2019:未解析的外部符号" public:void __cdecl well :: DataDump(int)" (?DataDump @ well @@ QEAAXH @ Z)在函数main
中引用src.exe:致命错误LNK1120:4个未解析的外部"
我猜测程序不知道cpp在哪里?我不包括课程' cpp代码中的任何其他地方,因为我的proc说只做.h'
我已经查看了有关堆栈溢出的其他类似问题,答案看起来很复杂而且不完全,有些与Visual Studio的混乱有关,但我使用的是Atom而不是视觉解决方案工作室。虽然如果某个地方有帖子,如果有人链接,我会尝试理解它。
来源: 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
由于可能出现的其他错误,我提前道歉,但我想我可以在这个奇怪的链接器错误之后修复它们。
这就是我构建文件的方式。就像手工制作的英雄一样:
@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%