Java AWT convient-il au rendu de jeu 2D?

8

[Republier cette question à partir de stackoverflow, car il a été souligné qu'elle s'adapte mieux ici.]

Je porte actuellement mon moteur de jeu 2D sur Java. J'ai regardé certaines des bibliothèques de jeux pointées ici sur stackoverflow. Cependant, ceux que j'ai examinés étaient plutôt simplistes et ne précisaient même pas s'ils prenaient en charge des éléments tels que la transparence alpha, j'ai donc décidé de porter mon rendu C ++ pour lequel j'avais déjà écrit la logique.

Ce moteur de rendu est un moteur de rendu purement logiciel qui utilise la mosaïque pour éviter un nouveau rendu inutile. J'ai optimisé ses performances de défilement en créant un "tampon hors écran" un peu plus grand que mon volet de sortie, et en plaçant ce tampon hors écran sur ma sortie à chaque image. De cette façon, je pouvais éviter de redessiner inutilement les carreaux simplement parce que je faisais défiler un pixel sur la carte.

J'ai utilisé l'AWT de Java pour l'implémenter, en utilisant une grande BufferedImage pour le tampon hors écran. L'utilisation du processeur est correcte (environ deux fois ce que j'avais en C ++), mais il y a un problème étrange avec le défilement continu, où toutes les secondes environ, le moteur de rendu restera en attente pendant environ 0,2 seconde.

Puisqu'il n'y a rien dans mon propre code qui se produirait pendant ces périodes, et puisque les pics disparaissent si je ne dessine pas mon tampon hors écran sur la vue principale, je peux seulement conclure que Java fait sa propre optimisation interne. Cependant, je ne suis pas sûr de ce qu'il fait, et je ne sais pas laquelle de mes propres optimisations je devrais supprimer pour me débarrasser des pointes. En outre, il se peut que java AWT n'ait pas été conçu avec un défilement FPS continu et élevé, et c'est entièrement inutilisable à cette fin.

Y a-t-il un moyen pour moi de me débarrasser de ces pointes?

cib
la source
4
Serait-ce le ramasse-miettes qui vous frappe?
bummzack
@bummzack: Peut-être. Dans le profileur, cela ressemble à ceci: i.imgur.com/EMxkA.png Cependant, je ne sais pas comment je réduirais cet effet, surtout s'il est provoqué par mes appels à graphics.drawImage
cib

Réponses:

4

Bien que je ne puisse pas être sûr sans regarder votre code, il semble que votre problème soit le garbage collector. En Java, vous avez de temps en temps des collectes de déchets majeures et mineures. Le mineur utilise une partie de votre processeur mais ne vous embête pas trop. Les principales collections peuvent être un vrai problème pour les applications en temps réel telles que les jeux, car elles suspendent tout pendant qu'elles fonctionnent.

Il existe deux options pour résoudre ce problème. Vous pouvez d'abord modifier la JVM pour vous assurer que moins de collections importantes ont lieu. Deuxièmement (et recommandé), vous pouvez vous assurer de ne pas laisser trop de déchets. Vérifiez simplement où dans votre application vous créez beaucoup d'objets (dans mes jeux, ce sont généralement les classes vector3) et assurez-vous de les réutiliser autant que possible (en particulier dans les boucles internes, etc.).

Pjotterke
la source
2

Oui.

Pour les jeux basés sur des sprites 2D, AWT peut être utilisé pour gérer le rendu avec grand effet. Il peut même être accéléré matériellement , selon le matériel disponible.

Sans code ni extraits de profilage détaillés, il est difficile de dire quel est le problème. Le mieux que je puisse faire est d'offrir quelques conseils de base pour travailler avec Java et AWT lors de la création de jeux.

Travailler avec le garbage collector

Le GC en Java est quelque chose que nous devons vraiment garder à l'esprit lorsque nous construisons nos jeux. Il s'exécutera périodiquement et recherchera les objets qui n'y ont aucune référence, et les supprimera de la mémoire. Ce processus de suppression est lent et est probablement la cause de l'attelage que vous rencontrez.

Ma suggestion est d'éviter de créer des références d'objet qui ne seront pas conservées pendant la durée de vie de l'exécution (ou du moins autant que possible). L'objectif idéal est de s'assurer que le GC n'a rien à faire à chaque fois qu'il s'exécute.

En pratique, vous pouvez vous retrouver avec de nombreuses variables statiques que vous réutilisez tout au long du jeu. Voici un exemple très artificiel de la façon dont j'ai tendance à gérer cela:

public final class Resources {
    public static Map<int, String> strings;
    public static Map<int, Texture> textures;
    public static Map<int, GameObject> objects;
    public static Map<int, SoundEffect> sounds;
}

Pendant le chargement des écrans, vous pouvez agrandir ou réduire vos Mapinstances à l'aide du newmot - clé. Mais pendant le jeu, vous voudrez éviter cela autant que possible. Si quelque chose est détruit pendant le jeu, placez un drapeau sur l'objet afin que vous sachiez que ce n'est pas quelque chose qui est actuellement actif. Si vous devez faire apparaître un nouvel objet, parcourez votre Mapjusqu'à ce que vous en trouviez un qui n'est pas actif, définissez ses propriétés et marquez-le comme actif.

C'est quelque chose que vous voudrez garder à l'esprit lorsque vous utilisez Java pour des applications sensibles aux performances, que vous utilisiez AWT, JavaFX ou OpenGL pour effectuer le rendu.

Toile

Pour AWT en particulier, je recommande fortement d'utiliser la classe Canvas pour tout restituer pour diverses raisons:

  • Vous avez un meilleur contrôle sur le rendu des choses. Cela signifie que vous pouvez écrire votre propre boucle de jeu et faire des choses comme l'interpolation, l'extrapolation, la limitation de débit, etc.
  • Il semble mieux fonctionner. J'ai pu obtenir plus de choses à l'écran à la fois à une fréquence d'images acceptable au lieu d'essayer d'animer un tas d'objets Label et Image.
  • Il est plus facile à intégrer dans les éditeurs. Pouvoir configurer un cadre avec des contrôles GUI normaux et pointer la logique de rendu de votre jeu sur un canevas m'a permis de réutiliser le code de rendu du jeu dans les outils de l'éditeur.
  • Il vous donne un accès facile à l'API Java2D (aka, la classe Graphics2D ).
Chiffrer
la source