多重定义错误; C ++使用Allegro

问题描述 投票:0回答:2

所以我正在使用Dev-C ++ 5.11和Allegro 4.2为我的计算机科学课做一个游戏,我已经到了项目的最后,我想最终修复一段时间以来一直存在的问题。我的代码使用单个.cpp文件相当长,但是当我尝试将我的函数放在一个单独的文件中时,我会收到一系列“多次定义''在这里首次定义'错误。我在网上看过,大多数有这个问题的人都把他们的.cpp文件包含在他们的主要或类似的东西中,但我没有这样做,也无法弄清楚为什么它不起作用。错误指向我在标头中声明的所有变量(位图以及char数组和整数)。

文件:

asteroidsMain.cpp
functions.cpp
asteroids.h

我也使用数据文件。

主文件:

#include <allegro.h>
#include <alfont.h> 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "asteroids.h"
#include "asteroids_data.h"

//Creating movement timer (also used for typing)
volatile long speed_counterA = 0;

void increment_speed_counterA() {
    speed_counterA++;
}
END_OF_FUNCTION(increment_speed_counterA); 

//Creating laser timer
volatile long speed_counterB = 0;

void increment_speed_counterB() {
    speed_counterB++;
}
END_OF_FUNCTION(increment_speed_counterB); 

//Creating asteroid timer
volatile long speed_counterC = 0;

void increment_speed_counterC() {
    speed_counterC++;
}
END_OF_FUNCTION(increment_speed_counterC); 


int main() {
    //Initializations
    allegro_init();
    alfont_init();
    set_color_depth(desktop_color_depth());
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);
    install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);
    install_keyboard();
    install_mouse();
    install_timer();

    //Movement timer
    LOCK_VARIABLE(speed_counterA);
    LOCK_FUNCTION(increment_speed_counterA);
    install_int_ex(increment_speed_counterA, BPS_TO_TIMER(60));
    //Laser firing timer
    LOCK_VARIABLE(speed_counterB);
    LOCK_FUNCTION(increment_speed_counterB);
    install_int_ex(increment_speed_counterB, BPS_TO_TIMER(60));
    //Asteroid generation timer
    LOCK_VARIABLE(speed_counterC);
    LOCK_FUNCTION(increment_speed_counterC);
    install_int_ex(increment_speed_counterC, BPS_TO_TIMER(60));

    //Randomizing seed
    srand(time(0));

    //Creating/loading BITMAPs formain game
    BITMAP *buffer = create_bitmap(800, 600);
    shipStopped = loadImage("shipStopped");
    shipMoving = loadImage("shipMoving");
    laserSprite = loadImage("laser");
    smallAsteroid = loadImage("small_Asteroid");
    medAsteroid = loadImage("med_Asteroid");
    largeAsteroid = loadImage("large_Asteroid");

    //General use variables for screen control
    int onScreen = 0, i = 0, j = 0;
    bool quit = false;

    //Retrieving and sorting scores
    numOfScores = getHighs(name, score);
    sortHighs(name, score);

    //Loads main screen
    onScreen = changeScreen(0);

    while (!quit) {
        //If there was an issue loading datafile, error is returned
        if (onScreen == -1) {
            return 1;
        }
        else if (onScreen == 0) {   
            while (onScreen == 0) {
                //Primary check is for quitting program, other buttons lead to separate screens
                if ((mouse_b & 1) && mouse_x > 400 - 75 && 
                mouse_x < 400 + 75 && mouse_y > 450 && mouse_y < 4505 + quitButton->h) { //For clicking Quit
                    quit = true;
                    onScreen = -2;
                }
                else if ((mouse_b & 1) && mouse_x > 400 - 75 && 
                mouse_x < 400 + 75 && mouse_y > 150 && mouse_y < 150 + playButton->h) { //For clicking Play
                    onScreen = changeScreen(2);
                }
                else if ((mouse_b & 1) && mouse_x > 400 - 75 && 
                mouse_x < 400 + 75 && mouse_y > 250 && mouse_y < 250 + highsButton->h) { //For clicking Highscores
                    onScreen = changeScreen(3);
                }
                else if((mouse_b & 1) && mouse_x > 400 - 75 && 
                mouse_x < 400 + 75 && mouse_y > 350 && mouse_y < 350 + creditsButton->h) { //For clicking Credits
                    onScreen = changeScreen(4);
                }
            }
        }
        else if (onScreen == 2) { //Difficulty choice screen
            if ((mouse_b & 1) && mouse_x > 600 - (playButton->w / 2) && 
                mouse_x < 600 + (playButton->w / 2) && mouse_y > 192 && mouse_y < 192 + playButton->h) {
                    onScreen = changeScreen(1);
        }
            else if ((mouse_b & 1) && mouse_x > 635 && mouse_x < 775 && 
            mouse_y > 575 - menuButton->h && mouse_y < 575) { //Returns to main menu
                onScreen = changeScreen(0);
            }
        }
        else if (onScreen == 3) { //Highscore screen
            if ((mouse_b & 1) && mouse_x > 635 && mouse_x < 775 && 
            mouse_y > 575 - menuButton->h && mouse_y < 575) { //Returns to main menu
                onScreen = changeScreen(0);
            }
        }
        else if (onScreen == 4) { //Credit screen
            if ((mouse_b & 1) && mouse_x > 635 && mouse_x < 775 && 
            mouse_y > 575 - menuButton->h && mouse_y < 575) { //Returns to main menu
                onScreen = changeScreen(0);
            }
        }
        else if (onScreen == 51) { //Game over screen

            if (points <= score[9]) {
                if ((mouse_b & 1) && mouse_x > 25 && mouse_x < 175 &&
                    mouse_y > 575 - menuButton->h && mouse_y < 575) { //Begins a new game
                    onScreen = changeScreen(2);
                }
                else if ((mouse_b & 1) && mouse_x > 635 && mouse_x < 775 &&
                         mouse_y > 575 - menuButton->h && mouse_y < 575) { //Returns to main menu
                    onScreen = changeScreen(0);
                }
            }
            else {
                if (mouse_b & 1) {
                    //Adding new highschore to array
                    score[9] = points;
                    strcpy(name[9], "");

                    if (numOfScores < 10) {
                        numOfScores++;
                    }
                    onScreen = changeScreen(52);
                }
            }
        }
        else if (onScreen == 52) {
            speed_counterA = 0;

            int keyEnt = 0, len = 0;
            char keyHold;

            //Text entering for highscore name, moves to next screen on enter
            while (!key[KEY_ENTER]) {
                //Preventing multiple printing of same key
                while (keypressed() && speed_counterA % 3 == 0) {
                    //Reading key from keyboard and making it useable
                    keyEnt = readkey();
                    keyHold = keyEnt & 0xff;

                    if (keyHold >= 32 && keyHold <= 126) { //Adding chars to name string
                        len = strlen(name[9]);

                        if (len < 19) { //Restricting the number of characters you can enter, beyond this does not save properly
                        name[9][len] = keyHold;
                        name[9][len + 1] = '\0';
                    }
                    }
                    else if (key[KEY_BACKSPACE]) { //Deleting if backspace char is pressed
                        name[9][len] = '\0';
                        len--;
                    }
                    clear_keybuf();
                }
                //Printing text
                textprintf_centre_ex(buffer, font, 400, 300, WHITE, -1, "What is your name: %s", name[9]);
                textprintf_centre_ex(buffer, font, 400, 500, WHITE, -1, "** press enter to conitue **");
                // Blit the buffer
                blit(buffer, screen, 0, 0, 0, 0, 800, 600); 
                clear(buffer);

            }
            onScreen = changeScreen(53);
        }
        else if (onScreen == 53) {
            if ((mouse_b & 1) && mouse_x > 25 && mouse_x < 175 &&
                mouse_y > 575 - menuButton->h && mouse_y < 575) { //Begins a new game
                onScreen = changeScreen(2);
            }
            else if ((mouse_b & 1) && mouse_x > 635 && mouse_x < 775 &&
                     mouse_y > 575 - menuButton->h && mouse_y < 575) { //Returns to main menu
                onScreen = changeScreen(0);
            }
        }
        else if (onScreen == 1) { //Game screen
            //Defining 
            Laser laser[50];
            Asteroid asteroid[10];

            //Initializing lasers and asteroids
            for (i = 0; i < 50; i++) {
                laser[i].pos.x = 0;
                laser[i].pos.y = 0;
                laser[i].angle = 0;
                laser[i].onScreen = false;
            }
            for (i = 0; i < 10; i++) {
                asteroid[i].pos.x = 0;
                asteroid[i].pos.y = 0;
                asteroid[i].angle = 0;
                asteroid[i].onScreen = false;
            }

            //Game specific variables, reset for every new game
            int move = 0, lasers= 0, asteroids = 0;
            float angle = 0;
            bool collide = false;

            points = 0;

            //Spawning ship when game screen loads
            Coordinate ship;
            ship.x = 400 - (shipStopped->w / 2);
            ship.y = 300 - (shipStopped->h / 2);

            //Reseting game timers
            speed_counterA = 0;
            speed_counterB = 0;
            speed_counterC = 0;

            while (onScreen == 1) { //Game screen
                while (speed_counterA > 0) {

                    //Ship movement
                    if (key[KEY_UP] && key[KEY_RIGHT]){
                        ship.y -= 3;
                        ship.x += 3;
                        angle = 32;
                    }
                    else if (key[KEY_UP] && key[KEY_LEFT]){
                        ship.y -= 3;
                        ship.x -= 3;
                        angle = 224;
                    }
                    else if (key[KEY_DOWN] && key[KEY_RIGHT]) {
                        ship.y += 3;
                        ship.x += 3;
                        angle = 96;
                    }
                    else if (key[KEY_DOWN] && key[KEY_LEFT]) {
                        ship.y += 3;
                        ship.x -= 3;
                        angle = 160;
                    }
                    else if (key[KEY_UP]){
                        ship.y -= 6;
                        angle = 0;
                    }
                    else if (key[KEY_RIGHT]) {
                        ship.x += 6;
                        angle = 64;
                    }
                    else if (key[KEY_LEFT]) {
                        ship.x -= 6;
                        angle = 192;
                    }
                    else if (key[KEY_DOWN]) {
                        ship.y += 6;
                        angle = 128;
                    }

                    //Laser movement
                    for (i = 0; i < 50; i++) {
                        laser[i] = moveLaser(laser[i]);
                    }

                    //Asteroid movement
                    for (i = 0; i < 10; i++) {
                        asteroid[i] = moveAsteroid(asteroid[i]);
                    }

                    speed_counterA--;
                }

                //Key trigger for laser firing, if is first as having timer first 
                //would cause many hits not to be properly registered especially if 
                //tapping too fast, this allows firing at will with a fastest firing of every 0.15s
                if (key[KEY_SPACE]) {
                    //Laser firing timer
                    while (speed_counterB > 9) {
                        //Laser shooting
                        laser[lasers] = fireLaser(angle, ship.x, ship.y);

                        if (lasers >= 49) {
                            lasers = 0;
                        }

                        lasers++;

                    speed_counterB -= 10;
                    }
                }   

                //Asteroid spawning counter
                while (speed_counterC > 59) { //Spawns an asteroiud every second

                    //Keeping asteroids within array range
                    if (asteroids >= 9){
                        asteroids = 0;
                    }

                    //Generating asteroid
                    asteroid[asteroids] = genAsteroid(1, -1);

                    asteroids++;
                    speed_counterC -= 60;
                }

                //If ship goes out top, it comes in bottom; vice versa
                if (ship.y <= 0 - ((shipStopped->h / 2))) {
                    ship.y += (600);
                }
                else if (ship.y >= 600 - ((shipStopped->h / 2))) {
                    ship.y -= (600);
                }

                //If ship goes out left, it comes in right; vice versa
                if (ship.x <= 0 - ((shipStopped->w / 2))) {
                    ship.x += (800);
                }
                else if (ship.x >= 800 - ((shipStopped->w / 2))) {
                    ship.x -= (800);
                }

                //Drawing lasers
                for (i = 0; i < 50; i++) {
                    if (laser[i].onScreen) {
                        rotate_sprite(buffer, laserSprite, laser[i].pos.x, laser[i].pos.y, ftofix(laser[i].angle)); 
                    }
                }

                //Drawing ship
                if (key[KEY_UP] || key[KEY_DOWN] || key[KEY_LEFT] || key[KEY_RIGHT]) {
                    rotate_sprite(buffer, shipMoving, ship.x, ship.y, ftofix(angle)); //Ship sprite with engines firing
                }
                else {
                    rotate_sprite(buffer, shipStopped, ship.x, ship.y, ftofix(angle)); //Ship sprite no flames

                }

                //Drawing asteroids
                for (i = 0; i < 10; i++) {
                    if (asteroid[i].onScreen == true) {
                        //Drawing sprite based on asteroid type
                        if (asteroid[i].type == 1) { //Large asteroid
                            draw_sprite(buffer, largeAsteroid, asteroid[i].pos.x, asteroid[i].pos.y);
                        }
                        else if (asteroid[i].type == 2) { //Medium asteroid
                            draw_sprite(buffer, medAsteroid, asteroid[i].pos.x, asteroid[i].pos.y);
                        }
                        else if (asteroid[i].type == 3) { //Small asteroid
                            draw_sprite(buffer, smallAsteroid, asteroid[i].pos.x, asteroid[i].pos.y);
                        }
                    }
                }

                //Checks bb collisions
                for (i = 0; i < 50; i++) {
                    for (j = 0; j < 10; j++) {
                        if (laser[i].onScreen && asteroid[j].onScreen) {
                            collide = checkCollision(asteroid[j].type, 0, asteroid[j].pos, laser[i].pos);
                            if (collide) {
                                laser[i].onScreen = false;
                                asteroid[j].onScreen = false;

                                points += 100 * asteroid[j].type;

                                //Splitting med or large asteroids into 2 asteroids one type down
                                if (asteroid[j].type < 3) { 
                                    asteroid[asteroids] = splitAsteroid(1, asteroid[j]);
                                    asteroid[j] = splitAsteroid(2, asteroid[j]);
                                    asteroids++;
                                }
                            }
                        }
                    }
                }

                //Printing score
                textprintf_ex(buffer, font, 10, 5, WHITE, -1, "Score: %d", points);
                textprintf_ex(buffer, font, 660, 5, WHITE, -1, "Press esc to quit");

                // Blit the buffer
                blit(buffer, screen, 0, 0, 0, 0, 800, 600); 
                clear(buffer);

                for (i = 0; i < 10; i++) {
                    if (asteroid[i].onScreen) {
                        collide = checkCollision(asteroid[i].type, 1, asteroid[i].pos, ship);

                        if (collide) {
                            onScreen = changeScreen(51);
                        }   
                    }
                }

                //To leave game screen and return to main menu
                if (key[KEY_ESC]) {
                    onScreen = changeScreen(0);
                }
            }
        }
    }

    //Freeing memory
    destroy_bitmap(playButton);
    destroy_bitmap(highsButton);
    destroy_bitmap(creditsButton);
    destroy_bitmap(quitButton);
    destroy_bitmap(shipStopped);
    destroy_bitmap(shipMoving);
    destroy_bitmap(laserSprite);
    destroy_bitmap(smallAsteroid);
    destroy_bitmap(medAsteroid);
    destroy_bitmap(largeAsteroid);

    return 0;
}
END_OF_MAIN()

头文件是:

#ifndef ASTEROIDS_H_
#define ASTEROIDS_H_

#define WHITE makecol(255, 255, 255)
#define BLACK makecol(0, 0, 0)

#include <allegro.h>
#include <alfont.h> 

//Made global so size pointers can be used throughout
BITMAP *playButton;
BITMAP *playAgainButton;
BITMAP *highsButton;
BITMAP *creditsButton;
BITMAP *quitButton;
BITMAP *menuButton;
BITMAP *shipStopped;
BITMAP *shipMoving;
BITMAP *laserSprite;
BITMAP *smallAsteroid;
BITMAP *medAsteroid;
BITMAP *largeAsteroid;

//Highscore variables are made global; technically bad, 
//but makes simplifies printing greatly
int score[10], numOfScores, points;
char name[10][20];

struct Coordinate {
    int x, y;
};

struct Laser {
    Coordinate pos;
    float angle;
    bool onScreen;
};

struct Asteroid {
    Coordinate pos;
    int type;
    int angle;
    bool onScreen;
};

int changeScreen(int toLoad);
BITMAP* loadImage(const char image[20]);
int getHighs(char name[][20], int high[]);
void sortHighs(char name[][20], int score[]);
void saveHighs(const char name[][20], const int score[], int numOfScores);
Laser fireLaser(float angle, int ship_x, int ship_y);
Laser moveLaser(Laser laser);
Asteroid genAsteroid(int difficulty, int type);
Asteroid splitAsteroid(int order, Asteroid asteroid);
Asteroid moveAsteroid(Asteroid asteroid);
bool checkCollision(int typeA, int typeB, Coordinate asteroid, Coordinate object);

#endif

函数文件归结为:

#include <allegro.h>
#include <alfont.h> 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "asteroids.h"
#include "asteroids_data.h"

/*~500 lines of functions*/

当我简单地将函数放在main之下时,一切都有效

编译日志的副本:

g++.exe -c asteroidsMain.cpp -o asteroidsMain.o -I"C:/Program Files (x86)/Dev-Cpp/MinGW64/include" -I"C:/Program Files (x86)/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"C:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include" -I"C:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++" -I"C:/Program Files (x86)/Dev-Cpp/include" -m32
g++.exe asteroidsMain.o functions.o -o POPE_Greg_Asteroids.exe -L"C:/Program Files (x86)/Dev-Cpp/MinGW64/x86_64-w64-mingw32/lib32" -L"C:/Program Files (x86)/Dev-Cpp/lib" -lalfont -lalleg -m32
functions.o:functions.cpp:(.bss+0x0): multiple definition of `playButton'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x0): first defined here
functions.o:functions.cpp:(.bss+0x4): multiple definition of `playAgainButton'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x4): first defined here
functions.o:functions.cpp:(.bss+0x8): multiple definition of `highsButton'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x8): first defined here
functions.o:functions.cpp:(.bss+0xc): multiple definition of `creditsButton'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0xc): first defined here
functions.o:functions.cpp:(.bss+0x10): multiple definition of `quitButton'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x10): first defined here
functions.o:functions.cpp:(.bss+0x14): multiple definition of `menuButton'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x14): first defined here
functions.o:functions.cpp:(.bss+0x18): multiple definition of `shipStopped'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x18): first defined here
functions.o:functions.cpp:(.bss+0x1c): multiple definition of `shipMoving'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x1c): first defined here
functions.o:functions.cpp:(.bss+0x20): multiple definition of `laserSprite'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x20): first defined here
functions.o:functions.cpp:(.bss+0x24): multiple definition of `smallAsteroid'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x24): first defined here
functions.o:functions.cpp:(.bss+0x28): multiple definition of `medAsteroid'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x28): first defined here
functions.o:functions.cpp:(.bss+0x2c): multiple definition of `largeAsteroid'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x2c): first defined here
functions.o:functions.cpp:(.bss+0x40): multiple definition of `score'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x40): first defined here
functions.o:functions.cpp:(.bss+0x68): multiple definition of `numOfScores'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x68): first defined here
functions.o:functions.cpp:(.bss+0x6c): multiple definition of `points'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x6c): first defined here
functions.o:functions.cpp:(.bss+0x80): multiple definition of `name'
asteroidsMain.o:asteroidsMain.cpp:(.bss+0x80): first defined here
collect2.exe: error: ld returned 1 exit status

C:\Users\Greg\Documents\Asteroids B\Makefile.win:25: recipe for target 'POPE_Greg_Asteroids.exe' failed
mingw32-make.exe: *** [POPE_Greg_Asteroids.exe] Error 1
c++ allegro
2个回答
1
投票

标头中声明的变量需要标记为extern并在单独的源文件中进行镜像。如果每个源文件都包含您的标头,则不同文件中将存在多个相同对象的定义,并且链接时将发生重新定义错误。


0
投票

在同一个项目中添加这些文件。

© www.soinside.com 2019 - 2024. All rights reserved.