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

RoughGuenni

Frischling

  • »RoughGuenni« ist der Autor dieses Themas

Beiträge: 14

Wohnort: Ochtendung

  • Private Nachricht senden

1

11.08.2017, 16:53

Unity3D Performance - typische Anfängerfehler?

Hallo,

ich entwickele einen sidescrolling 3D-Platformer in Unity und bin sehr unzufrieden mit der Performance des aktuellen Stands. Das betrifft v.a. die Ladebildschirme, aber auch in Runtime lässt die Performance zu wünschen übrig.

Ich nutze derzeit Occlusion Culling und ein Großteil des Lichts wird als Lightmap gebaked. Daran sollte es also eigentlich nicht liegen.

Da ich noch recht grün hinter den Ohren bin (im Game Developement, ansonsten bin ich schon gar nicht mehr so frisch :) ): Gibt es irgendwelche typischen Anfängerfehler, die v.a. Newbies über die Performance verzweifeln lässt? Ich bin mittlerweile ziemlich ratlos.

Tiles

Treue Seele

Beiträge: 168

Wohnort: none

  • Private Nachricht senden

2

11.08.2017, 18:22

Hallo Rough Guenni,

Licht und Schatten hast du ja schon erwähnt. Schatten Baken ist ne gute Sache zum Performance sparen. Realtime GI ist allerdings eins dieser Ressourcenhogs. Das zieht einfach. Sieht natürlich aber auch hübsch aus :)

Als erstes würde ich mir mal die Grafiken und die Drawcalls anschaun. Da lässt sich mit den Materialien, Shadern und Meshes immer einiges rausoptimieren. Ein Material = Ein Drawcall . Ein Mesh auch ein Drawcall. Und manche Shader ... . Ist eigentlich das Mesh Limit für dynamic Batching immer noch so elend niedrig bei 300 Vertices?

Eine geringere Texturgrösse kann auch einiges an Performance bringen und die Ladezeiten erhöhen. Zu Risiken und Nebenwirkungen reden sie mit ihrem Grafiker und verhauen ihren Programmierer ...

Ich weiss nicht ob du es verwendet, aber das Unity Terrain ist berüchtigt dafür viel Performance zu futtern. Bei der Distanz für ab wann Gras und Bäume als Billboard dargestellt werden kann man auch einiges einsparen. Und natürlich an der Baumgeometrie als solches ...

Und ansonsten musst du halt die Ressourcenhogs finden. Und sehen was da noch zu optimieren ist. Da ist jedes Game ein wenig anders. Da gibts kein Patentrezept. Dafür kann man den Profiler nehmen. Der listet dir auf welche Komponenten wieviel Performance ziehen. Und der ist ja seit Unity 5 auch in der Free Version dabei.

Du kannst es aber auch einfach nach der groben Holzhammermethode probieren. Einfach das Game starten, und eine Komponente nach der anderen abschalten und die FPS dabei im Auge behalten. Wenn die Performance plötzlich nach oben schnalzt hast du das Problemkind gefunden. Und kannst dir genauer anschauen wo man da noch optimieren kann. Manchmal rennt eine Funktion zum Beispiel die ganze Zeit mit obwohl sie das von der Spielmechanik her gar nicht müsste. Sowas zum Beispiel :)

Ich hoffe mal das hilft dir ein wenig weiter :)

Liebe Grüsse

Tiles
Free Game Graphics, Freeware Games https://www.reinerstilesets.de

Renegade

Alter Hase

Beiträge: 494

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

3

11.08.2017, 18:32

Hallo RoughGuenni,
benutzt du bereits Unity 2017? Wenn nein, solltest du defintiv updaten. In der aktuellen Version wurde massiv an der Performance, dank neuem Multi Threading, geschraubt.
Verwendest du selbst geschriebene Skripte oder Plugins zur Umsetzung deines Platformers? Gerade bei selbsgeschriebenen Skripten neigen Anfänger zu einigen performance-kritischen Codezeilen aus Unwissen (Find Methoden, GetComponents in Routinen, unnötige Nutzung von Co-Routinen). Ein paar Auszüge aus Skripten mit denen du arbeitest wären aufschlussreich.
Der Unity Profiler ist sehr hilfreich um Performance Probleme ausfindig zu machen.
Liebe Grüße,
René

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Renegade« (11.08.2017, 18:37)


RoughGuenni

Frischling

  • »RoughGuenni« ist der Autor dieses Themas

Beiträge: 14

Wohnort: Ochtendung

  • Private Nachricht senden

4

11.08.2017, 19:59

Danke erstmal für das flotte Feedback!

Ist eigentlich das Mesh Limit für dynamic Batching immer noch so elend niedrig bei 300 Vertices?


äh ... ? :D Sorry, kann ich nicht beantworten. Ich hab' jetzt nicht jeden Aspekt der Frage verstanden, dafür hab' ich wohl noch zu viel Grün hinter den Ohren.

Eine geringere Texturgrösse kann auch einiges an Performance bringen und die Ladezeiten erhöhen. Zu Risiken und Nebenwirkungen reden sie mit ihrem Grafiker und verhauen ihren Programmierer ...
Aktuell benutzen wir für den Background ein prozedural generiertes Material - mein "Grafiker" und ich arbeiten bereits daran, das etwas schicker und gezielter zu gestalten. Vielleicht bringt uns das dann ja tatsächlich etwas Boost.

Terrains benutzen wir für das Game nicht. Aber der Profiler ist mal 'ne dolle Idee. Ich erinnere mich, mir den schon vor einiger Zeit mal angeschaut und nix verstanden zu haben - aber ich hab' ja inzwischen dazu gelernt. Danke für den Hinweis.

Da das Projekt noch recht übersichtlich ist - ich werde es erstmal mit der Holzhammermethode versuchen!

benutzt du bereits Unity 2017?


Jepp, tu ich. :)

Die Skripte schreibe ich selbst - das ist meine Kernaufgabe. :) Ich soll die herzeigen? Oha. 8| Ich habe zwar nicht den Eindruck, dass die sonderlich löblich zusammengeschrieben sind, aber wir sind ja unter uns. :) Nee, Quark. Man wächst allein an Kritik, also immer her damit!

Das folgendes Skript ist episch lang. Inzwischen weiß ich, dass man so was eigentlich nicht machen soll. Es ist mein längstes, daher dachte ich, es repräsentiert ganz gut meinen Stand.

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public bool facingRight = true;

    //Using Healthpotions
    public HealthManager healthManager;
    public GameObject HealthPotionEffect;

    //Move
    [HideInInspector] public float move;
    [HideInInspector] public float currentSpeed;
    public float maxSpeed;    
    public float jumpForce;

    //Footstep-Effects
    public GameObject FootStepEffect;
    public GameObject Foots;
    [SerializeField] private float stepEffectTimer;
    [SerializeField] private float stepEffectCounter;
    //Stomping-Effect
    [SerializeField] private GameObject jumpImpactEffect;

    //Knockback
    public float knockbackX;
    public float knockbackY;
    public float knockbackLength;
    public float knockbackCount;
    [HideInInspector] public bool knockFromRight;

    //as usual
    [HideInInspector] public Animator anim;
    [HideInInspector] public Rigidbody rb;

    //Grounded?
    public bool grounded;

    //On a ladder?
    [HideInInspector]public bool onLadder;
    private float climbSpeed;
    private float currentClimbSpeed;
    [SerializeField] private float maxClimbSpeed;

    //modifier for horizontal moving if on ladder or something else
    [SerializeField] private float runMod;
    

    //Range-Attack
    public Transform firePoint;
    public GameObject Dagger;
    private float shotDelay;
    [SerializeField] private float shotDelayCounter;


    void Start ()
    {
        //Set Player in right direction
        transform.eulerAngles = new Vector3(0, 90, 0);

        anim = GetComponent<Animator>();
        rb = GetComponent<Rigidbody>();
        healthManager = FindObjectOfType<HealthManager>();

        stepEffectCounter = stepEffectTimer;
        currentSpeed = maxClimbSpeed;
        onLadder = false;
        grounded = true;
        shotDelay = 0;
                
    }
    

    void Update()
    {
        
        //Grounded-Animationen setzen
        if (grounded)
           anim.SetBool("Ground", grounded);        

        if (!grounded)
           anim.SetBool("Ground", false);

        //Run-Animation setzen
        anim.SetFloat("Speed", Mathf.Abs(move));


        //MOVE
        //Move-Variable erfassen
        move = Input.GetAxisRaw("Horizontal");

        //Footstep-Effects
        stepEffectCounter -= Time.deltaTime;
        if (Mathf.Abs(move) >= 0.1 && grounded && stepEffectCounter <=0)
        {   
            Instantiate(FootStepEffect, Foots.transform.position, Foots.transform.rotation);
            stepEffectCounter = stepEffectTimer;
        }
        //Do Move wenn kein Knockback durch Damage aktiv ist
        if (knockbackCount <= 0)
        {
            rb.velocity = new Vector2(move * currentSpeed, rb.velocity.y);
            anim.SetBool("Knockback", false);       
          

        } else
        //Do if theres is knockback
        {
            if (knockFromRight)
            {
                anim.SetBool("Knockback",true);
                rb.velocity = new Vector2(-knockbackX, knockbackY);
                move = 0.0f;
            }
            if (!knockFromRight)
            {
                anim.SetBool("Knockback", true);
                rb.velocity = new Vector2(knockbackX, knockbackY);
                move = 0.0f;
            }
            knockbackCount -= Time.deltaTime;            
        }

        //Flip Animations
        if (move > 0 && !facingRight)
            Flip();
        else if (move < 0 && facingRight)
            Flip();

        //JUMP
        if (grounded && (Input.GetKeyDown(KeyCode.Space) || Input.GetButtonDown("Jump")))
            Jump();


        //RANGE
        if ((Input.GetKeyDown(KeyCode.Return) || Input.GetButtonDown("Fire2")) && shotDelay <= 0)
            Range();
        
        shotDelay -= Time.deltaTime;

        //MELEE
        if (Input.GetKeyDown(KeyCode.E) || Input.GetButtonDown("Fire3"))
            anim.SetTrigger("Melee");

        //CLIMB          
        if (onLadder)
            Climb();

        if (!onLadder)
            ResetClimb();
        
        
        //USE HEALTH POTION
        if (((Input.GetKeyDown(KeyCode.H) || Input.GetButtonDown("Potion")) && HealthPotionManager.healthPotions > 0))
        {
            UseHealthPotion();
        }

    }

    //FUNKTIONEN

    public void Range()
    {
        anim.SetTrigger("Range");
        shotDelay = shotDelayCounter;
    }

    public void Jump()
    {
        anim.SetBool("Ground", false);
        rb.AddForce(new Vector2(0, jumpForce));
    }

    public void Climb()
    {
            //change the player rotation
            transform.eulerAngles = new Vector3(0, 0, 0);
            //change the player position
            transform.position = new Vector3(transform.position.x, transform.position.y, -0.2f);

            //change scale like in flip function, so the player alway looks to background on a ladder
            Vector3 theScale = transform.localScale;
            theScale.x = 0.75f;
            theScale.z = 0.75f;
            transform.localScale = theScale;

            currentClimbSpeed = maxClimbSpeed;
            //gravity off
            rb.useGravity = false;

            //horizontal move reduction                 
            if (!grounded)
            {
                currentSpeed = runMod;

                //JUMP ON LADDER
                if (Input.GetKeyDown(KeyCode.Space) || Input.GetButtonDown("Jump"))
                {
                    currentSpeed = maxSpeed;
                    rb.useGravity = true;
                    anim.SetBool("Ground", false);
                    rb.AddForce(new Vector2(0, jumpForce));
                    onLadder = false;
                    currentClimbSpeed = 0;
                }
            }

            if (grounded)
            {
                currentSpeed = maxSpeed;
            }

            //climbspeed works like horizontal movement
            climbSpeed = currentClimbSpeed * Input.GetAxisRaw("Vertical");
            rb.velocity = new Vector2(rb.velocity.x, climbSpeed);
            // OnLadder-Anim
            anim.SetBool("OnLadder", true);
            //Climbing-Anim
            anim.SetFloat("climbSpeed", Mathf.Abs(climbSpeed));        
    }

    public void ResetClimb()
    {
            transform.position = new Vector3(transform.position.x, transform.position.y, 0);

            if (facingRight)
            {
                Vector3 theScale = transform.localScale;
                theScale.x = 0.75f;
                theScale.z = 0.75f;
                transform.localScale = theScale;
            }
            if (!facingRight)
            {
                Vector3 theScale = transform.localScale;
                theScale.x = -0.75f;
                theScale.z = -0.75f;
                transform.localScale = theScale;
            }

            //set the player rotation back
            transform.eulerAngles = new Vector3(0, 90, 0);
            currentSpeed = maxSpeed;
            //just to be sure, climbspeed equals zero
            currentClimbSpeed = 0;
            //gravity on
            rb.useGravity = true;
            anim.SetBool("OnLadder", false);
            anim.SetFloat("climbSpeed", 0);       
    }

    public void Flip()
    {
        if (!onLadder)
        {
            facingRight = !facingRight;
            Vector3 theScale = transform.localScale;
            theScale.x *= -1;
            theScale.z *= -1;
            transform.localScale = theScale;
        }
    }

    //Animation-Event: Stomping on ground after jumping/falling
    public void StompingOnGround()
    {
        Instantiate(jumpImpactEffect, Foots.transform.position, Foots.transform.rotation);        
    }

    //Animation-Event: Instantiate Dagger and throw it at the right time of animation
    public void ThrowDagger()
    {
        Instantiate(Dagger, firePoint.position, firePoint.rotation);
    }

    public void UseHealthPotion()
    {
        HealthPotionManager.AddHealthPotions(-1);
        healthManager.AddhealthPoints(100);
        Instantiate(HealthPotionEffect, transform.position, transform.rotation);
    }

    //let the player move with a platform (make the parent of the player the moving platform, so that it inherits the platforms movement)
    private void OnTriggerStay(Collider other)
    {
        if (other.transform.tag == "MovingPlatform")
        {              
            //inherit movement
            transform.parent = other.transform;
            
            //if player moves or jump stop inheriting
            if ((Input.GetKeyDown(KeyCode.Space) || Input.GetButtonDown("Jump")) || Mathf.Abs(move) >= 0.1)
            {
                transform.parent = null;
            }           

        }
    }
    
    private void OnTriggerExit(Collider other)
    {
        if (other.transform.tag == "MovingPlatform")
        {
            transform.parent = null;
        }
    }
    
    


}

Tiles

Treue Seele

Beiträge: 168

Wohnort: none

  • Private Nachricht senden

5

11.08.2017, 20:38

Zitat

äh ... ? :D Sorry, kann ich nicht beantworten. Ich hab' jetzt nicht jeden Aspekt der Frage verstanden, dafür hab' ich wohl noch zu viel Grün hinter den Ohren.


Das war nur ein dezenter Hinweis mal nach dynamic Batching zu suchen ;)

static / dynamic Batching bedeutet dass bestimmte Objekte mit einem Material zu einem Drawcall zusammengefasst werden können. Mit static Batching lassen sich alle statischen Objekte und deren Materialien auf einen Rutsch darstellen. Das macht Unity eigentlich automatisch wenn ich mich noch recht erinnere.

Und mit dem dynamic batching lässt sich eben alles bewegte zu einem Drawcall zusammenfassen. Dynamic Batching hatte allerdings zu der Zeit als ich noch Unity benutzt habe ein Verticeslimit von 300 Vertices pro Mesh damit das funktioniert hat :)
Free Game Graphics, Freeware Games https://www.reinerstilesets.de

RoughGuenni

Frischling

  • »RoughGuenni« ist der Autor dieses Themas

Beiträge: 14

Wohnort: Ochtendung

  • Private Nachricht senden

6

11.08.2017, 21:15

Das macht Unity eigentlich automatisch wenn ich mich noch recht erinnere.


So weit ich das verstanden habe, isses tatsächlich so. Danke für den Tipp mit dem dynamic Batching; das Thema hatte ich bislang gar nicht auf dem Schirm.

Ich habe jetzt einmal die Holzhammermethode angewandt. An dem prozeduralen Material liegt es nicht - ohne den Objekten, die dieses benutzen, beträgt die Ladezeit 41 Sekunden, mit diesen Objekten ebenso. Nur marginale Besserung bei der Deaktivierung anderer Objekte - egal ob static oder dynamisch.

Ich benutze zwischen den Leveln jeweils eine Scene als "Loader", weil ich will, dass alles fertig geladen ist, bevor der Spieler den ersten Schritt im Folgelevel macht. Nun habe ich durch das Lightmapping und die vielen statischen Objekte ja recht viel zum Laden, da weniger während der Laufzeit berechnet wird. Das Gerüst des Skripts, das ich in dieser Lade-Szene benutze, hatte ich einst aus einem Unity-Forum. Möglicherweise kann es daran liegen?

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class LevelLoader : MonoBehaviour {

    
    public string levelToLoad;
    

        void Start()
    {                
        //start a coroutine that will load the desired scene.
         StartCoroutine(LoadNewScene());
    }


    // The coroutine runs on its own at the same time as Update() and takes an integer indicating which scene to load.
    IEnumerator LoadNewScene()
    {

       
        // Start an asynchronous operation to load the scene that was passed to the LoadNewScene coroutine.
        AsyncOperation async = SceneManager.LoadSceneAsync(levelToLoad);

        // While the asynchronous operation to load the new scene is not yet complete, continue waiting until it's done.
        while (!async.isDone)
        {
            yield return null;
        }

    }

}


Die Werte, die mir der Profiler ausspuckt, sind für mich nicht sonderlich aussagekräftig, da mir Referenzen fehlen (Camera.Render = 41% ist der führende Wert), damit muss ich mich noch genauer auseinander setzen.

RoughGuenni

Frischling

  • »RoughGuenni« ist der Autor dieses Themas

Beiträge: 14

Wohnort: Ochtendung

  • Private Nachricht senden

7

11.08.2017, 21:46

Allmälig wird es gruselig.

Ich deaktiviere (über den Haken im Inspektor) jedes Objekt in der Scene und es hat null Effekt auf die Ladezeit.

Lade ich hingegen von meiner Load-Scene aus eine neu erstelle Scene mit lediglich einem Primitive drin, dann lädt diese Scene blitzschnell. :hmm:


Werde Objekte auch tatsächlich nicht mehr mitberechnet, wenn sie im Inpector deaktiviert werden?

Tiles

Treue Seele

Beiträge: 168

Wohnort: none

  • Private Nachricht senden

8

12.08.2017, 08:55

Deaktivieren hilft nichts. Geladen werden die Objekte ja dann trotzdem. Sie sind dann nur inaktiv. Du müsstest sie schon aus der Szene löschen. Vorher Backup machen ...

Zitat

Ich benutze zwischen den Leveln jeweils eine Scene als "Loader", weil ich will, dass alles fertig geladen ist, bevor der Spieler den ersten Schritt im Folgelevel macht. Nun habe ich durch das Lightmapping und die vielen statischen Objekte ja recht viel zum Laden, da weniger während der Laufzeit berechnet wird. Das Gerüst des Skripts, das ich in dieser Lade-Szene benutze, hatte ich einst aus einem Unity-Forum. Möglicherweise kann es daran liegen?


Die Frage hast du dir im Grunde schon selber beantwortet. Du hast das Script ausgemacht und es hat nichts verändert. Du lädst wohl einfach viel. Wenn du das schneller haben willst musst du die Datenmenge reduzieren. Zum Beispiel indem du in einer geringeren Qualität lightmappst. Oder indem du die Texturgrössen runterstellst. Das kann man auch im Inspector in Unity machen. Oder indem du die Meshes verkleinerst. Oder gleich das ganze Level.

Es gibt auch die Möglichkeit Objekte zu streamen. Dann werden sie erst bei Bedarf geladen. Stichwort Resources.Load. Das ist aber eigentlich für einen simplen Sidescroller ein wenig Overkill. Das ist eher was für Open World MMO's.

Ich würde sagen schau erst mal nach den schon genannten Punkten, auch die von Renegade genannten wie zum Beispiel GetComponent. Komponenten kann man auch anders an die Strippe kriegen, zum Beispiel indem man die entsprechenden Objekte über eine Variable im Inspector verbindet. Aber genau da sind wir wieder in den tiefsten Details. Das wird hier einfach zu viel auf einmal. Mach erst mal die groben Dinger, dann beschäftige dich mit dem Profiler, und dann gehts an die Mikrooptimierungen :)

LG

Tiles
Free Game Graphics, Freeware Games https://www.reinerstilesets.de

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Tiles« (12.08.2017, 09:41)


Renegade

Alter Hase

Beiträge: 494

Wohnort: Berlin

Beruf: Certified Unity Developer

  • Private Nachricht senden

9

12.08.2017, 11:11

Hallo RoughGuenni,
scheinbar muss dein Level recht groß sein und die Datenmenge dementsprechend. Das deaktivieren von GameObjects hilft dir dabei nicht, weil die Daten mit der Szene dennoch geladen werden müssen. Die einfachste Variante wäre, dass Level zu verkleinern und in mehrere Szenen zu packen/zu laden. Es ist möglich Szenen async und additiv (Siehe Default Parameter LoadSceneMode in LoadSceneAsync) zu laden.

C#-Quelltext

1
2
//mischt die weitereSzene mit in die aktuell geladene, sprich additive
LoadSceneAsync("weitereSzene", LoadSceneMode.Additive);

Das von dir gezeigte Beispielskript zum Laden von Szenen kann vereinfacht werden, denn Start Methoden können bereits für sich selbst als CoRoutine behandelt werden:

C#-Quelltext

1
2
3
4
5
6
7
public class LevelLoader : MonoBehaviour {
    public string levelToLoad;
    
    IEnumerator Start() {
         yield return SceneManager.LoadSceneAsync(levelToLoad);
    }
}
Liebe Grüße,
René

RoughGuenni

Frischling

  • »RoughGuenni« ist der Autor dieses Themas

Beiträge: 14

Wohnort: Ochtendung

  • Private Nachricht senden

10

12.08.2017, 20:12

N'abend Ihr Beiden. :)

Das von dir gezeigte Beispielskript zum Laden von Szenen kann vereinfacht werden, denn Start Methoden können bereits für sich selbst als CoRoutine behandelt werden:


Das klappt wunderbar, danke! Da muss man erstmal drauf kommen...

Ihr habt mir jede Menge Anhaltspunkte gegeben, die ich jetzt nacheinander durch- bzw. ausprobieren werde. Da sind so einige Themen dabei, mit denen ich mich näher befassen möchte und muss. Ich will das ja nicht nur einfach machen, sondern auch verstehen. Wird also ein paar Tage dauern; ich sag' Bescheid, was es war und was geholfen hat.

Vielen Dank erstmal bis hierhin. Cheerz!

Werbeanzeige