Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Timmyew

Treue Seele

  • »Timmyew« ist der Autor dieses Themas

Beiträge: 128

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

1

26.09.2020, 20:50

C++ (LNK2001 Fehler) finde keine Lösung

Guten Abend,

ich habe vor kurzem begonnen C++ zu erlernen und bin daher dementsprechend unerfahren.
Bisher besitze ich nur Kenntnisse in diverse andere Programmiersprachen, wie beispielsweise Object Pascal(Delphi).
Momentan bin ich dabei mir das Spieleprogrammieren beizubringen und den Umgang mit der SDL Bibliothek.

Folgende Klassen kann ich ohne den oben genannten Fehler nicht instanziieren:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma once
#include <vector>

class Entity {
private:
    bool active;
public:
    Entity();
    ~Entity();

    void draw();
    void update();
    bool isActive() { return active; };
    void destroy() {active = false; };
};

class EntitiyManager {
private:
    std::vector<Entity> entities;

public:
    ~EntitiyManager() {entities.clear();}

    void refresh() { 
        entities.erase(std::remove_if(entities.begin(), entities.end(), [](Entity& mEntity) {return !mEntity.isActive(); }), entities.end());
    }

    void draw() {
        for (int i = 0 < entities.size(); i++;)entities[i].draw();
    }

    void update() {
        for (int i = 0 < entities.size(); i++;)entities[i].update();
    }

    Entity& addEntity() {
        Entity* e = new Entity();
        entities.emplace_back(std::move(*e));
    }
};


Die Klasse in der ich diese Klassen instanziieren:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "Game.h"

Game::Game(const char* title, int xpos, int ypos, int width, int height, bool fullscreen) {
    int flags = 0;

    if (fullscreen) {
        flags = SDL_WINDOW_FULLSCREEN;
    }

    if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
        std::cout << "Subsystems Initialised..." << std::endl;

        window = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
        if (window) {
            std::cout << "Window created!" << std::endl;
        }

        renderer = SDL_CreateRenderer(window, -1, 0);
        if (renderer) {
            SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
            std::cout << "Renderer created!" << std::endl;
        }

        isRunning = true;

    }
    else {
        isRunning = false;
    }

    fps = new Fps();
    texManager = new TextureManager(renderer);
    entityManager = new EntitiyManager(); //Wenn ich den Bereich auskommentiere, taucht der Fehler nicht mehr auf.
}

Game::~Game() {
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    SDL_Quit();
    std::cout << "Game Cleaned!" << std::endl;
}

void Game::handleEvents() {
    SDL_Event event;
    SDL_PollEvent(&event);

    switch (event.type) {
    case SDL_QUIT:
        isRunning = false;
    default:
        break;
    }
}

void Game::update() {
    if ((updateCount % 10000) == 0) {

        std::cout << count << " | Fps: " << fps->getFps() << std::endl;
        updateCount = 0;
    }

    updateCount++;
    count++;
}

void Game::render() {
    fps->update();
    
}


Hierzu gibt es noch eine Headerdatei:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#ifndef Game_hpp
#define Game_hpp

#include "SDL.h"
#include "Fps.h"
#include "SDL_image.h"
#include <iostream>
#include <stdio.h>
#include "TextureManager.h"
#include "ECS.h"

class Game{
public:
    Game(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
    ~Game();

    void handleEvents();
    void update();
    void render();

    bool running() { return isRunning; };

    SDL_Renderer* renderer;

private:
    bool isRunning = false;
    int count = 0;
    int updateCount = 0;


    SDL_Window* window;
    Fps* fps;
    TextureManager* texManager;
    EntitiyManager* entityManager;
    

};
#endif


Das Ziel der EntityManager- und Entityklasse ist ein Entity Component System zu entwickeln.

Mit freundlichen Grüßen,
Timmyew. :)

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

2

26.09.2020, 21:09

Und die Fehlermeldung lautet?
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

Timmyew

Treue Seele

  • »Timmyew« ist der Autor dieses Themas

Beiträge: 128

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

3

26.09.2020, 21:21

LNK2001
»Timmyew« hat folgendes Bild angehängt:
  • error.png

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

4

26.09.2020, 23:09

Der Linker vermisst die Definition des Destruktors (zu erkennen am Zeichen ~ vor dem Klassennamen) des Typs Entity. Und er hat Recht, in Deinem Code oben hast Du Konstruktor und Destruktor des Types "Entity" nur deklariert (== ihr Vorhandensein angekündigt), aber nicht definiert (== implementiert, ausprogrammiert, mit Code gefüllt). Das musst Du nachreichen. Oder Konstruktor/Destruktor einfach weglassen. Immerhin machen die ja nichts. Ein einfaches

Quellcode

1
bool active = false;
reicht als Konstruktor auch für diesen schlichten Typ.

Der Code im Allgemeinen liest sich, als würdest Du aus der Java-Welt kommen. Beispiel: Du legst eine Entity mit new an, movest deren Inhalt dann in eine Instanz im Vector, und hast dann nicht die Entity wieder gelöscht. Die beiden Zeilen könnten mit einer Zeile zusammengefasst werden:

Quellcode

1
entities.emplace_back();


emplace() und Verwandte erstellen eine neue Instanz direkt im Vektor. Dabei wird der Konstruktor mit der gegebenen Parameterliste gefüttert.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

Jonathan

Community-Fossil

  • Private Nachricht senden

5

27.09.2020, 00:06

Der Code im Allgemeinen liest sich, als würdest Du aus der Java-Welt kommen. Beispiel: Du legst eine Entity mit new an, movest deren Inhalt dann in eine Instanz im Vector, und hast dann nicht die Entity wieder gelöscht. Die beiden Zeilen könnten mit einer Zeile zusammengefasst werden:


Wenn man ein Objekt auf dem Stack erstellt und dann in den Container packt, besteht dann nicht dankt Konzepten wie Copy elision sowieso eine ziemlich gute Chance, dass es auf den selben Assembler-Code wie ein emplace_back hinausläuft? Ich würde da nicht unbedingt zu 100% drauf vertrauen, aber wenn der Code dadurch aus irgendeinem Grund besser lesbarer wäre und nicht super geschwindigkeitskritisch ist, kann man es glaube ich darauf ankommen lassen.

Allgemein stimme ich Schrompf zu, der Code sieht recht nach Java aus. IMO sollte man in C++ überhaupt kein new mehr verwenden sondern direkt make_unique bzw. make_shared. Dauert etwas sich daran zu gewöhnen und Compilerfehler zu vermeiden, dafür sieht man aber direkt wenn etwas schief läuft und hat am Ende insgesamt robusteren Code.
Lieber dumm fragen, als dumm bleiben!

Timmyew

Treue Seele

  • »Timmyew« ist der Autor dieses Themas

Beiträge: 128

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

6

27.09.2020, 02:02

Ihr seit Genies :D
Es hat funktioniert ^^.
Ich bin mir bei der smart Pointer Sache nicht so sicher, weil ich es nicht kenne und es in der Delphi Welt auch nicht in der Form existiert ^^.
Haben smart Pointer denn irgendwelche Nachteile was sich auf die Effizienz auswirkt?
Zum Thema Effizienz wollte ich noch gesagt haben, dass ich meines Wissens sehr darauf achte, um ein performantes Spiel zu entwickeln.
Natürlich ist das jetzt bei Breakout egal, nur wenn ich später bei anderen Projekten mehrere tausend Objekte verwalten muss, muss es performant laufen.
Ich werde die konstruktive Kritik von euch aufjedenfall umsetzen!
Wie bereits erwähnt bin ich erst seit kurzem in der C++ Welt unterwegs.
Um genau zu sein erst seit dieser Woche. ^^

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Timmyew« (27.09.2020, 02:27)


Jonathan

Community-Fossil

  • Private Nachricht senden

7

27.09.2020, 12:07

Haben smart Pointer denn irgendwelche Nachteile was sich auf die Effizienz auswirkt?

Ich sag jetzt einfach mal 'nein'.

Auf Performance zu achten ist natürlich gut, aber das ist eben auch ein sehr kompliziertes Thema bei dem man auch sehr genau wissen muss was hinter den Kulissen passiert. Aber die high-level Designentscheidungen dürften sowieso einen viel größeren Einfluss auf die Geschwindigkeit, als die low-level Implementierungen.

Ich würde dir raten erstmal einfach weiter zu machen und darauf zu achten wartbaren und robusten Code zu schreiben. Wenn du dann an irgendeiner Stelle wirklich Performanceprobleme bekommst, kann man das ja problemspezifisch hier nochmal diskutieren. Das Thema ist sowieso viel zu komplex um von Anfang an alles komplett optimal zu machen aber das ist eben auch nicht wirklich nötig.

Btw: Es gibt bei Klassen wie unique_ptr hauptsächlich um 'Ownership', eine effiziente Art der Speicherverwaltung. Zu dem Stichpunkt findet man eine Menge Artikel, hier ist ein ziemlich theoretischer, aber du findest sicherlich auch andere: https://www.stroustrup.com/resource-model.pdf
Lieber dumm fragen, als dumm bleiben!

8

28.09.2020, 14:12

C-/C++-Quelltext

1
for (int i = 0 < entities.size(); i++;) entities[i].draw();

Ich möchte diese For-Schleife für die Nachwelt festhalten. Wenn entities nicht leer ist, setzt du i auf 1 und erhöhst es um 1. Dann zeichnest du also entities[2], entities[3], ... bis du einen Speicherzugriffsfehler bekommst.

Richtig wäre

C-/C++-Quelltext

1
for(size_t i = 0; i < entities.size(); ++i) entities[i].draw();
oder direkt

C-/C++-Quelltext

1
for(auto& entity : entities) entity.draw();
Cube Universe
Entdecke fremde Welten auf deiner epischen Reise durchs Universum.

Werbeanzeige