0

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%
Joe
  • 29,416
  • 12
  • 68
  • 88
  • 1
    Post the relevant source here and please format your code and errors. It reads like you declared functions in a class but didn't properly implement them. – AndyG Feb 12 '15 at 04:48
  • Ah, let me try again. I apologize, and will post the sources. – Zilarrezko Feb 12 '15 at 07:41
  • I don't understand why this is marked as a duplicate. The post it directs me to doesn't help me, or at least I can't understand the answers. and he doesn't even mention Link error 2019. Am I really this much of a script kiddie that I can't understand this stuff? Is it laughable that I don't understand the error? – Zilarrezko Feb 12 '15 at 09:05
  • Tetrimino.cpp needs to `#include "tetrimino.h"`, and well.cpp needs to `#include "well.h"` – AndyG Feb 12 '15 at 12:49
  • alright. That would have been one of the errors after, so thank you for that. Though still didn't fix the linker problem. – Zilarrezko Feb 13 '15 at 17:10
  • You have put your `#define TETRIMINO_H` and `#define WELL_H` in the wrong places as well. Put them right after the `#ifndef` line. Leave `#endif` where it's at. – AndyG Feb 13 '15 at 17:39
  • Still didn't fix my problem, is it running fine for you guys? – Zilarrezko Feb 14 '15 at 03:42
  • I think I'm narrowing where the error is. If you guys follow handmade hero, I'm building my project like that. I think I have to compile the other cpp files? – Zilarrezko Feb 14 '15 at 04:00
  • 1
    I figured it out after days of messing with it. It was a compile thing, and there was no reason to mark it as a duplicate because no one else had this problem. I would like to make an answer for this problem, but I think since some genius marked it as a duplicate I can't reply with an answer. – Zilarrezko Feb 16 '15 at 06:30

0 Answers0