L'entité doit-elle gérer son propre mouvement?

Dec 06 2020

Je construis actuellement un jeu au tour par tour simple avec une salle composée d'un tableau 2D d'objets Tile. Ceux-ci peuvent être WallTile ou FloorTile. Les objets Tile ont un voisin nord, est, sud et ouest. Les FloorTiles ont une pile d'entités afin que je puisse facilement dessiner l'entité supérieure.

Maintenant, je me demande, mon joueur est une entité, lorsque le joueur se déplace, le joueur doit-il gérer cette logique ou le jeu qui contient mon joueur?

Dans le premier cas, ce serait quelque chose du genre:

class Player : Entity {
    public Tile CurrentLocation

    public bool CanMoveTo(Direction) {
        // Let's say that direction is East
        return CurrentLocation.EastNeighbour == FloorTile
    }

    // This method does the actual move
    public void MoveTo(Direction)
}

Dans le second cas, ce serait comme ceci:

class Game {
    public Player Player;
    public Room Room;

    public void Update() {
        // Lets say we get direction from some input from somewhere
        if Room.TileAt(player.Y, player.X) is FloorTile then MoveThere()
    }
}

Je ne sais pas vraiment quelle est la plus belle des deux options. Au départ, je pense à la première solution. Toute aide ou astuce serait appréciée.

Réponses

4 Philipp Dec 06 2020 at 11:26

Il n'y a pas de bonnes ou de mauvaises façons de faire les choses. Seuls les moyens qui fonctionnent pour vous ou qui ne fonctionnent pas pour vous.

Il existe plusieurs philosophies concurrentes dans l'architecture de jeu grand public.

A: Architecture orientée objet

Chaque entité doit être représentée par un objet. Ces objets doivent contenir toute leur propre logique, encapsuler leur état interne et communiquer avec d'autres objets via des interfaces bien définies. Le moteur de jeu principal appelle simplement les méthodes "Update" et "Render" de toutes les entités dans une boucle et laisse ensuite les entités faire le reste.

Lorsque vous avez des objets qui partagent certaines fonctionnalités, vous le feriez généralement par héritage - en extrayant la fonctionnalité commune dans une classe de base commune. Par exemple, vous voudrez peut-être avoir une classe Player et une classe Enemy qui héritent toutes deux d'une classe Combatant qui contient tout le code de combat et hérite de Entity qui contient le code de base du mouvement. Et Enemy serait probablement une classe abstraite qui ne contient que la logique commune à tous les ennemis, avec les différents types d'ennemis et leurs comportements uniques implémentés dans des classes héritant d'Enemy.

Fondamentalement, la façon dont vous êtes censé faire la POO par le livre.

Ce style est fréquemment vu chez les développeurs issus du développement d'applications, car c'est le style prédominant là-bas. Et ce qui fonctionne pour les applications n'est pas nécessairement complètement faux pour les jeux.

B: architecture entité-composant

Ce style préfère la composition à l'héritage . Une entité n'est pas un objet, c'est une collection d'objets avec chaque objet implémentant une fonctionnalité différente de cette entité. Vous n'avez donc pas de classe "Player" implémentant tout ce qu'un joueur peut faire. Vous avez une entité générique avec un "Sprite", un "Mover", un "Shooter", un "Hitpoints" et un "PlayerInput".

L'avantage de cette approche est que les composants sont très faciles à mélanger et à assortir pour créer de nouveaux types d'entités de jeu. Ceci est très utile pour les itérations rapides de la conception de votre jeu. C'est l'approche préférée de certains moteurs de jeux populaires. Comme Unity, par exemple.

C: architecture Entité-Composant-Système

Une entité doit être un ensemble de composants tout comme dans l'architecture «Entité-Composant». Mais dans cette architecture, ces composants ne devraient être que des détenteurs de données stupides. Généralement sous forme de structures avec uniquement des variables publiques et aucune méthode. Toute la logique devrait être dans les systèmes. Chaque système est responsable de la gestion d'un type de composants ou d'un ensemble de composants. Par exemple, vous avez un MovementSystem qui met à jour le composant Position de chaque entité avec un composant Movement.

Mais ce n'est qu'une simplification excessive. Si vous voulez en savoir plus, consultez la question "Qu'est-ce que l'ECS pur?" . Vous pouvez également consulter d'autres questions sous notre balise entity-component-system .

L'approche ECS est actuellement très à la mode. L'argument principal en est qu'il permet des optimisations de performances très soignées (en particulier en ce qui concerne la localisation mémoire et le multithreading) sans sacrifier la modularité et la vitesse d'itération de l'approche Entité-Composant. Mais l'inconvénient est qu'une architecture ECS solide et flexible nécessite pas mal de code d'architecture qui s'exécute «en coulisse» et qui peut être difficile à implémenter pour les débutants.

Lequel devriez-vous utiliser?

C'est quelque chose dont vous avez besoin pour comprendre cela par vous-même. Mais quelle que soit l'approche que vous choisissez pour votre jeu, vous feriez bien de vous y tenir. Évitez les modèles d'architecture mixtes dans votre jeu lorsque cela est possible.

Turing Dec 09 2020 at 19:08

Cela dépend essentiellement de la quantité de données traversant votre réseau de jeu. Tout multijoueur massif doit garder une trace de qui est où faire quoi toujours (sinon une triche massive s'ensuivra). Cependant, recevoir et envoyer des paquets du serveur à chaque client (ce que l'on appelle un serveur auteur) est rarement pratique pour un certain nombre d'utilisateurs significatifs. Ainsi, la philosophie semble être la quantité de logique que vous pouvez faire contrôler par le joueur sans affecter les autres joueurs. En d'autres termes, ce qui vous affecte et vous seul (à l'exception du pillage) peut être géré par le client. Alors que tout ce qui affecte plusieurs joueurs doit être géré par le serveur. Ou, s'il n'est pas manipulé, au moins autorisé avant tout effet.