IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Architecture simple pour créer un petit jeu


Sujet :

C#

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut Architecture simple pour créer un petit jeu
    Bonjour,

    J'ai en projet d'écrire un petit jeu histoire d'élargir mes connaissances en C#.

    Après avoir tenté d'écrire un petit moteur graphique avec GDI et tombé à moins de 10 fps dès que j'ai voulu commencer à dessiner quelques formes simples, je me suis tourné vers SharpDX, en utilisant la partie 2D.

    J'ai "à peu près" compris comment ça marchait d'un point de vue dessin. J'ai pas trop de souci pour dessiner une scène, et avec quelques mini-optimisations, je suis à 1500fps (pour une scène vide et statique, certes), mais tout de même plus complèxe que celle de GDI qui m'avait fait tomber à moins de 15fps... De ce côté, pour le moment "tout va bien".

    En revanche, c'est pour le reste.

    En effet, avec le tuto GDI que j'avais trouvé, j'avais bien cerné l'endroit et la manière de déclencher deux thread séparés : un pour le moteur graphique, et un pour le moteur du jeu lui-même.

    Seulement, avec les tutos que j'ai pu trouver sur SharpDX, j'ai du tout casser, et je n'arrive pas à comprendre :
    - où créer mon thread du moteur de jeu
    - comment accéder depuis le moteur graphique aux données du moteur de jeu
    - comment renvoyer au moteur de jeu les actions utilisateur (clic souris, etc.)

    Voici mon fichier "program.cs" :

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
     
    using System;
    using System.Windows.Forms;
     
    using SharpDX;
    using SharpDX.DXGI;
    using SharpDX.Direct3D;
    using SharpDX.Direct3D11;
    using SharpDX.Direct2D1;
    using SharpDX.Windows;
    using Device = SharpDX.Direct3D11.Device;
    using FactoryD2D = SharpDX.Direct2D1.Factory;
    using FactoryDXGI = SharpDX.DXGI.Factory1;
     
    namespace MyGame
    {
        static class Program
        {
            static void Main()
            {
                // Create render target window
                var form = new RenderForm("MyGame");
     
                // Create swap chain description
                var swapChainDesc = new SwapChainDescription()
                {
                    BufferCount = 2,
                    Usage = Usage.RenderTargetOutput,
                    OutputHandle = form.Handle,
                    IsWindowed = false,
                    ModeDescription = new ModeDescription(System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width,System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm),
                    SampleDescription = new SampleDescription(1, 0),
                    Flags = SwapChainFlags.AllowModeSwitch,
                    SwapEffect = SwapEffect.Discard
                };
     
                // Create swap chain and Direct3D device
                // The BgraSupport flag is needed for Direct2D compatibility otherwise new RenderTarget() will fail!
                Device device;
                SwapChain swapChain;
                Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, swapChainDesc, out device, out swapChain);
     
                // Get back buffer in a Direct2D-compatible format (DXGI surface)
                Surface backBuffer = Surface.FromSwapChain(swapChain, 0);
                RenderTarget renderTarget;
     
                // Create Direct2D factory
                using (var factory = new FactoryD2D())
                {
                    // Get desktop DPI
                    var dpi = factory.DesktopDpi;
     
                    // Create bitmap render target from DXGI surface
                    renderTarget = new RenderTarget(factory, backBuffer, new RenderTargetProperties()
                    {
                        DpiX = dpi.Width,
                        DpiY = dpi.Height,
                        MinLevel = SharpDX.Direct2D1.FeatureLevel.Level_DEFAULT,
                        PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Ignore),
                        Type = RenderTargetType.Default,
                        Usage = RenderTargetUsage.None
                    });
                }
     
                // Disable automatic ALT+Enter processing because it doesn't work properly with WinForms
                using (var factory = swapChain.GetParent<FactoryDXGI>())   // Factory or Factory1?
                {
                    factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAltEnter);
                }
     
                renderTarget.Transform = Matrix3x2.Identity;
                GraphicEngine ge = new GraphicEngine(renderTarget);
     
                // Rendering function
                RenderLoop.Run(form, () =>
                {
                    renderTarget.BeginDraw();
     
                    ge.DrawScene();
     
                    renderTarget.EndDraw();
     
                    swapChain.Present(0, PresentFlags.None);
                });
     
                renderTarget.Dispose();
                swapChain.Dispose();
                device.Dispose();
            }
        }
    }

    J'ai bien compris que mon "RenderLoop.Run" correspondait à la boucle qui lançait le moteur graphique.

    Mais je ne suis pas habitué à cette syntaxe. Du coup je vois pas comment je peux lancer un thread en parallèle et interagir avec le contenu de mon Run()...

  2. #2
    Membre chevronné
    Avatar de PixelJuice
    Homme Profil pro
    Ingénieur .NET & Game Designer
    Inscrit en
    Janvier 2014
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur .NET & Game Designer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 648
    Points : 2 170
    Points
    2 170
    Par défaut
    As-tu essayer de te pencher sur XNA ?

    Certes, XNA n'est pas maintenu officiellement (du moins par Microsoft) mais ça reste un excellent framework pour débuter la dedans.Ca m'a l'air plus simple que SharpDX a première vue (je ne connais pas vraiment SharpDX non plus).

    Terraria , ainsi que Magicka , ont été fait en XNA , pour te donner une idée.

  3. #3
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 194
    Points
    5 194
    Par défaut
    bonjour

    Attention, faire du Multithread au niveau d'un jeu peut-être assez dangereux suivant ce que tu mets dans tes threads.

    En général, le principe d'une boucle de jeu est la suivante:

    1 / Gestion des actions du jeu (par exemple déplacement de la position des objets, etc...
    2 / Rendu de la scène

    J'ai hyper simplifié mais en gros, t'as une partie "métier" ou tu mets à jour les données, une partie ou tu prends en compte les entrées utilisateurs et une partie ou tu fais le rendu.

    Pourquoi dis-je qu'il faut faire attention avec le multi-thread ? c'est parce que tu peux rapidement être dans des situations ou ton rendu graphique va devoir accéder à des objets partagés entre thread... souvent, pour résoudre ce type de problème, on a une routine qui gère plusieurs buffer et qui fait le transfert entre ces buffers. Ainsi, celà peut éviter qu'une donnée soit mise à jour alors qu'elle est utilisé par un autre thread.

    C'est pourquoi "la solution" d'avoir une boucle est souvent la première approche dans la réalisation d'un jeu...

    Voilà

  4. #4
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 493
    Points
    5 493
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    - où créer mon thread du moteur de jeu
    - comment accéder depuis le moteur graphique aux données du moteur de jeu
    - comment renvoyer au moteur de jeu les actions utilisateur (clic souris, etc.)
    a) Tu n'as qu'à créer un thread avant RenderLoop.Run
    b) Voulais-tu dire "comment synchroniser les données" ? Si oui, the Monz a déjà formulé la façon de faire la plus courante (dupliquer les objets du jeu pour fournir une copie en lecture seule au thread de rendu).
    c) Il suffit de s'abonner aux événements de Form. Attention, ceux-ci seront levés sur le thread UI, qui doit être ton thread de rendu si je ne m'abuse. Il faudrait vérifier dans la doc de SharpDX.

  5. #5
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Merci pour vos réponses.

    En fait, je souhaite faire un petit jeu de "gestion" (du genre Simcity, etc.)

    Je veux donc avoir un vitesse constante (genre 1 jour = 5 secondes).

    Le souci, c'est que si je veux un jeu fluide, je vais avoir mettons 20 images par seconde au minimum.

    Hors, les actions dans le jeu (mise à part la GUI) n'ont pas besoin de tourner plus d'une fois par "jour" (donc 1 fois toutes les 5 secondes et non 20 fois par seconde). Je pense par exemple à l'accroissement de la population, les changements économiques, etc.

    Pire, une fois le jeu "complexe", le traitement qui doit tourner une fois toutes les 5 secondes risque de tourner plus de 1/20 de seconde.

    Donc je peux pas me contenter d'une boucle avec un test genre "je fais les calculs relatifs au jeu une fois sur 100", car ça va freezer une fois toutes les 5 secondes.

    Et inversement, lorsque la partie graphique devient dense et qu'il faut plus de 1/20 seconde pour dessiner une image, je ne veux pas que l'échelle de temps s'allonge avec des jours qui durent non plus 5 secondes mais 10 ou 20 secondes.

    D'où l'idée de faire deux thread distincts, qui tournent chacun à leur rythme.

    Pour la synchronisation des données entre threads, je voyais plutôt des lock {} mais d'un point de vue performances, la recopie d'objets me semblent en effet bien meilleure. Merci pour l'idée.

    Bon, quand j'aurai le temps de m'y replonger, je vous tiendrai au courant de mes avancées/problèmes

  6. #6
    Membre chevronné
    Avatar de PixelJuice
    Homme Profil pro
    Ingénieur .NET & Game Designer
    Inscrit en
    Janvier 2014
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur .NET & Game Designer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 648
    Points : 2 170
    Points
    2 170
    Par défaut
    Je suis d'accord avec TheMonz , le multi-threading dans un jeu c'est dangereux et a mon avis dans ton cas pas très utile.

    J'ai codé quelques Shoot Em Up ou il y avait d’énorme calculs de collisions a toutes les frames , et de plus pas vraiment optimisé , je peux te dire que tu peux pousser assez loin avant de te soucier des performances.

    Pour tes calculs toute les 5 secondes , il suffit de cadencer ça avec (pseudo code) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    TimeSpan intervalleCalcul = TimeSpan.FromMilliseconds(5000);
    TimeSpan derniereIntervalle;
     
     
            private void Calcul()
            {
                if (derniereIntervalle + intervalleCalcul < tempsTotal)
                {
                    // tes calculs
                    derniereIntervalle = tempsTotal;
                }
            }
    Vu que le jeu a déjà mis un timer pour voir le temps écoulé , tu peux faire comme ça.

Discussions similaires

  1. recherche logiciel simple pour créer jeu 2D
    Par ayr99 dans le forum Logiciels de création de jeux vidéo
    Réponses: 10
    Dernier message: 31/05/2021, 00h15
  2. Aide pour concevoir un petit jeu en C
    Par samy100 dans le forum Projets
    Réponses: 11
    Dernier message: 30/10/2019, 11h22
  3. Le plus simple pour créer un service web ?
    Par goeland444 dans le forum Services Web
    Réponses: 0
    Dernier message: 22/07/2008, 15h43
  4. Réponses: 19
    Dernier message: 14/09/2007, 03h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo