Créer un niveau multijoueur 2D en boucle transparente?


15

Une discussion a récemment eu lieu sur la façon de créer un jeu multijoueur à défilement horizontal 2D pouvant avoir une conception de niveau en boucle (pensez à Starbound et à la façon dont leurs mondes sont en boucle).

Je pensais que le moyen le plus simple serait d'avoir une carte rectangulaire avec des zones de déclenchement qui pourraient téléporter les joueurs d'un côté à l'autre. Cependant, le problème évident de cette approche est le fait d'avoir plusieurs joueurs à la fois sur le bord de la carte. Vous ne voulez pas simplement téléporter les joueurs les uns devant les autres et vous auriez besoin d'un moyen de transporter les joueurs sans faire disparaître d'autres joueurs.

Pour ajouter cette idée et résoudre le problème, j'ai proposé ce qui suit: avoir une zone de déclenchement (carré rouge dans l'image) où les joueurs pourront voir une "zone de clonage" (carré vert). Dans ce carré vert, les objets du côté opposé de la zone de déclenchement seraient copiés dans sa zone de clonage correspondante (visible avec les formes A et B). Lorsqu'un joueur arrive au bord de départ de la "zone clone", il est téléporté de l'autre côté de la carte.

image

Dans cet exemple, le joueur 2 penserait voir le joueur 1, mais il verrait en fait son clone et vice versa.

Cela semblait un peu extrême et complexe pour le problème à résoudre. Ma question est maintenant de savoir si cette solution est une bonne approche pour résoudre le problème, ou existe-t-il un moyen plus simple de résoudre ce problème?


Les joueurs sont-ils autorisés à reculer dans une zone précédente?
XiaoChuan Yu

ouais, ça va et vient donc ça donne une sorte d'effet "marcher autour du monde". Similaire à la façon dont un monde est lié aux étoiles
KenQueso

2
Avez-vous pensé à faire du monde un grand cercle? ou traiter le niveau comme un grand cercle et le traduire en une scène 2D plate?
Nzall

ne pouvez-vous pas toujours aligner la position de la caméra avec le lecteur contrôlé?
Ali1S232

Réponses:


16

Ce système avec tous ces déclencheurs semble un peu trop compliqué et sujet aux erreurs.

Vous pouvez envelopper la position du joueur en utilisant modulo avec quelque chose comme playerPositionX = playerPositionX % mapWidth

De cette façon, lorsque votre joueur atteindra playerPosition == mapWidthle playerPositionsera réinitialisé à 0.

Cette solution pourrait être étendue à l'ensemble du système de rendu.


1
cela ne poserait-il pas le problème de voir de près les joueurs dont la position réinitialisée se téléporter?
KenQueso

Comment étendre cela au système de rendu?
Mikael Högström

Vous pourriez avoir un joueur toujours au centre de la caméra et faire enrouler la carte. Comme une carte en mode civilisation sur terre. Une autre approche pourrait être de rendre la partie visible d'un joueur des deux côtés de la carte.
Exaila

4
@ MikaelHögström Rendez juste comme d'habitude, mais les choses proches du bord droit doivent être rendues une deuxième fois à gauche (c'est-à-dire à pos - map_width).
Mario

1
N'importe où dans votre code que vous recherchez «quel objet se trouve à cette coordonnée» ou «quelles sont les coordonnées de cet objet», vous le feriez xcoord% mapWidth. Il est difficile de dire sans votre code, mais cela le rendrait probablement correctement.
Tin Man

13

La solution canonique consiste à utiliser des portails . Dans votre exemple, il n'y a qu'un seul niveau, sauf qu'il existe un portail reliant les extrémités gauche et droite.

Tout ce qui se déplace à travers ce portail aura ses coordonnées traduites à l'autre extrémité du portail, de sorte que si quelque chose se déplace vers la gauche à travers le portail, il réapparaîtra sur le côté droit du niveau et vice versa.

Votre caméra doit également prendre en charge les portails; si le portail est à l'intérieur de la caméra, il doit restituer des parties du niveau de chaque côté du portail. Si vous connaissez les éditeurs d'images pour les graphiques en mosaïque sans couture, c'est la même chose ici.

La partie fastidieuse est que tout ce qui concerne la distance ou le cheminement devra également prendre en charge les portails. Cela comprend l'IA, les algues en ligne de visée, l'atténuation du son, etc.

Ce qui est bien avec les portails, c'est qu'ils sont très puissants. Le moteur de construction l'a utilisé pour simuler des niveaux à plusieurs étages, bien qu'il ne s'agisse pas d'un "vrai" moteur 3D. Certains moteurs modernes utilisent également des portails pour créer des espaces non euclidiens; Portal et Antichamber sont des exemples notables en 3D.


2
Si vous écoutez le commentaire du jeu de portail, une partie du fonctionnement des portails est implémentée en clonant ce qui est visible à travers le trou. (mais pour des raisons de physique plutôt que de rendu)
Mooing Duck

6

N'oubliez pas que ce que vous affichez à l'écran et ce qui est en mémoire sont deux choses totalement différentes. Imaginez que vous ayez une fenêtre que vous devez remplir avec des données sur le monde. Vous remplissez la fenêtre de gauche à droite. Pendant que vous analysez vos données pour remplir le monde, si vous atteignez la fin du monde, retournez simplement au début de vos données. Utilisant un opération modulo est idéale. N'oubliez pas que vous devez le faire pour tout . Projectiles, rayons, joueurs, physique; ils ont tous besoin d'avoir leurs positions enveloppées lors du franchissement des frontières du monde.

Chaque joueur partage des données, mais a sa propre perspective des données. Leurs fenêtres sont remplies différemment selon leur position dans le monde.

Cela signifie qu'il n'est pas nécessaire de créer des clones ou de téléporter qui que ce soit. Essentiellement , vous êtes en train de créer des clones, tout en rendant les caractères sur les écrans les uns des autres.


3

Déconnectez le rendu du monde et vous pouvez effectuer un rendu enveloppant et correct sans recourir à des artefacts de clonage ou de téléportation.

Premièrement, dans votre monde, vous avez un monde de taille fixe, de 0à Width. Chaque fois qu'un objet descend en dessous de 0, vous l'enveloppez jusqu'à la fin, et chaque fois qu'un objet est terminé, Widthenveloppez-le au début. Cela signifie que tous les objets logiques de votre monde sont toujours à portée 0...Width.

Deuxièmement, pour le rendu, vous modulerez la position. Ainsi, le côté gauche de l'écran est "Base" et le côté droit est "Base + Taille". Vous regardez donc à travers votre monde pour tout ce qui se trouve dans cette plage. Vous rechercherez en fait la plage modulo, qui la remappe 0...Width.

L'astuce lors de la recherche consiste à renvoyer la position de l'objet par rapport à la Base côté gauche. Cela se convertit en coordonnées locales de l'écran afin que le rendu lui-même n'ait pas à se soucier du modulo, seule la recherche le fait.

Vous n'avez pas besoin de cloner quoi que ce soit car chaque moteur de rendu ne traite que l'objet en un seul emplacement.

Si votre monde est produit en segments ou en utilisant des structures 3D, vous devrez le segmenter. Il ne s'agit donc pas d'un bloc cohérent, mais il peut être déplacé pour s'adapter à ce rendu. Vous n'avez pas besoin de beaucoup de blocs, au minimum 2.


1

Je pense que la seule approche raisonnable serait d'implémenter votre monde enveloppé dans une structure de données sous-jacente complètement transparente pour le jeu et l'utilisateur. Donc, sur certains bas niveau, vous avez une fonction mapCoordinate () qui enveloppe vos coordonnées réelles dans votre ressource de carte sous-jacente ...

Donc, si votre monde actuel ne fait que 10 unités de large, le joueur et le jeu ne le sauront pas. Pour le joueur, le monde est infini - et si le jeu demande ce qui est en position 15 - la fonction sous-jacente traduira cette demande, modulo10 et donnera pack à l'objet en position 5.

Donc, pour toute la logique du jeu et tout le reste, c'est comme si vous aviez un grand monde infini, où il se trouve qu'il y a des copies de tout.


1

Ce n'est pas tout à fait la même chose, mais j'ai implémenté quelque chose de similaire lors d'un game jam. Le jeu avait des joueurs se déplaçant sur un petit niveau circulaire, enroulé autour lorsque le joueur a atteint une position «x» de pi. Le rendu a été facile car nous venons de tout rendre, puis tournons une caméra offset pour suivre ce qui se passe. Vous pouvez implémenter quelque chose de similaire, comme cela a été suggéré ci-dessus:

  • Lors du dessin, vérifiez la position de la caméra et déterminez ce qui doit être dessiné, en tenant compte de la position de la caméra et de son champ de vision.
  • Dans les cas où la caméra voit au-delà du `` bord '' de la carte, sélectionnez une quantité appropriée de contenu de l'autre côté du monde pour dessiner sur ce bord, généralement simplement en ajoutant ou en soustrayant la largeur du niveau à leur position.
  • La logique de jeu doit être consciente de cette couture et s'y adapter comme mentionné dans d'autres réponses. Les cas particuliers à connaître sont les collisions où un objet est d'un côté, mais entre en collision avec un objet de l'autre côté.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.