Hintergrundbild fuer 2D-pong verlangsamt spielfluss



  • ok danke für den tip tko werds mal versuchen.

    #pragma once
    
    namespace pongtest 
    {
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	/// <summary>
    	/// Zusammenfassung für Form1
    	///
    	/// Warnung: Wenn Sie den Namen dieser Klasse ändern, müssen Sie auch
    	///          die Ressourcendateiname-Eigenschaft für das Tool zur Kompilierung verwalteter Ressourcen ändern,
    	///          das allen RESX-Dateien zugewiesen ist, von denen diese Klasse abhängt.
    	///          Anderenfalls können die Designer nicht korrekt mit den lokalisierten Ressourcen
    	///          arbeiten, die diesem Formular zugewiesen sind.
    	/// </summary>
    	public ref class Form1 : public System::Windows::Forms::Form
    	{
    	private:
    		Graphics^ grafik;  //Für den Ball
    		Graphics^ grafik2; //Für das HintergrundBild
    
    		Image^ bild;
    		Image^ hintergrund;
    
    		int xKoordinate, yKoordinate;
    		int speed;
    
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    			//
    			//TODO: Konstruktorcode hier hinzufügen.
    			//
    
    			//das Bild für den Ball das bewegt wird
    			bild = Image::FromFile ("ball.bmp");
    
    			//das Hintergrundbild für die Form
    			hintergrund = Image::FromFile ("drago.jpg"); 
    
    			xKoordinate = 0; 
    			yKoordinate = 0; 
    
    			//den Speed des Ball setzen
    			speed = 10;
    
    			// das Paint-Ereignis "Void zeichnen" auslösen lassen
    			Paint += gcnew PaintEventHandler (this, &Form1::zeichnen);
    
    			// das Flackern verhindern
    			SetStyle (ControlStyles::UserPaint, true);
    			SetStyle (ControlStyles::AllPaintingInWmPaint, true);
    			SetStyle (ControlStyles::DoubleBuffer, true);
    		}
    
    	protected:
    		/// <summary>
    		/// Verwendete Ressourcen bereinigen.
    		/// </summary>
    		~Form1()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    
    	private: System::Windows::Forms::Timer^  timerBall;
    	private: System::ComponentModel::IContainer^  components;
    
    	private:
    		/// <summary>
    		/// Erforderliche Designervariable.
    		/// </summary>
    
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Erforderliche Methode für die Designerunterstützung.
    		/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			this->components = (gcnew System::ComponentModel::Container());
    			this->timerBall = (gcnew System::Windows::Forms::Timer(this->components));
    			this->SuspendLayout();
    			// 
    			// timerBall
    			// 
    			this->timerBall->Enabled = true;
    			this->timerBall->Interval = 1;
    			this->timerBall->Tick += gcnew System::EventHandler(this, &Form1::timerBall_Tick);
    			// 
    			// Form1
    			// 
    			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
    			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    			this->BackColor = System::Drawing::SystemColors::Control;
    			this->BackgroundImageLayout = System::Windows::Forms::ImageLayout::None;
    			this->ClientSize = System::Drawing::Size(632, 366);
    			this->ForeColor = System::Drawing::Color::Transparent;
    			this->Name = L"Form1";
    			this->Text = L"Form1";
    			this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &Form1::Form1_Paint);
    			this->ResumeLayout(false);
    
    		}
    #pragma endregion
    
    	private: System::Void zeichnen (System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) 
    			 {
    				 grafik = e->Graphics;
    				 grafik->DrawImage (bild, xKoordinate, yKoordinate); 
    			 }
    
    	private: System::Void timerBall_Tick(System::Object^  sender, System::EventArgs^  e) 
    			 {
    				 xKoordinate = xKoordinate + speed;
    				 yKoordinate = yKoordinate + speed;
    
    				 Invalidate ();
    			 }
    
    	//das Hintergrundbild für die Form zeichnen 
    	private: System::Void Form1_Paint (System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) 
    			 {
    				 grafik2 = e->Graphics;
    				 grafik2->DrawImage (hintergrund, 0, 0);
    			 }
    	};
    }
    

    So pictureBoxen sind alle weg, und es scheint wirklich was geholfen zu haben.

    Allerdings ruckelt der Ball aber nun, wenn ich den Speed beispielsweise auf 10 setze...

    Weis jemand weiter 😕

    gruß



  • ich glaube, die Performance, die du aus dem c++.net rausgeholt hast, ist schon fast an der Grenze. Ein Experte mag mir gerne widersprechen, aber diese Konstellation ist nicht für schnelle Grafikanforderungen geschaffen, dafür würde ich andere Frameworks bemühen. Es heißt ja nicht ohne Grund "Formular" und nicht "2D-Grafikengine" 😉

    Tut mir Leid, habe da auch keine weiteren Tipps 😞



  • jo, ok danke Alex. Ist halt nur blöd, weil benutz ich die pictureBoxen und SetBounds() ruckelt der Ball zwar nicht, kann aber dafür kein hintergrundbild hinzufügen.
    Mit der anderen Variante kann ich zwar Hintergrundbilder hinzufügen, dafür ruckelt der Ball dann aber.
    Ist schon verrückt, zumal ich halt schon soweit gekommen bin und mich das jetzt nervt, das ich das Projekt wegen dieser Sache nicht zuende bringen kann.

    Badestrand schrieb:

    C++/CLI ist an sich schon geeignet für 2D- und auch 3D-Spiele!
    Ich weiß nicht, ob es passend ist, aber gibt's nicht sowas wie DirectX-Controls? Damit müsste es schnell genug gehen 🙂

    DirectX ? Kommt für mich vielleicht erst in 2 Jahren in Frage...

    Naja und auf unmanaged C++ oder C# umzusteigen um das DarkGDK bzw. das XNA Framework zu nutzen fällt erstmal auch flach, da ich wie gesagt gradeerstmal die Grundlagen von C++/CLI erlernt hab und nicht jetzt schon ein neues "Kapitel" in sachen unmanaged C++ bzw. C# einschlagen will.



  • AlexanderM schrieb:

    ich glaube, die Performance, die du aus dem c++.net rausgeholt hast, ist schon fast an der Grenze. Ein Experte mag mir gerne widersprechen, aber diese Konstellation ist nicht für schnelle Grafikanforderungen geschaffen, dafür würde ich andere Frameworks bemühen.

    Habs endlich geschafft 😋



  • Stell Dir vor, Du hättest in einem Forum jemanden gefunden der Dein Problem hat.
    Du liest diesen mit Begeisterung weil es genau auf Dein Problem passt. Und dann
    endet die Diskussion mit einem

    "Ich habs geschafft"



  • Immerhin hat er seine E-Mailadresse angegeben. 🙂



  • Knuddlbaer schrieb:

    Stell Dir vor, Du hättest in einem Forum jemanden gefunden der Dein Problem hat.
    Du liest diesen mit Begeisterung weil es genau auf Dein Problem passt. Und dann
    endet die Diskussion mit einem

    "Ich habs geschafft"

    hast ja recht, wollts aber nachreichen musste eben nur schnell weg.

    So, als erstes hab ich die Variante mit meinen pictureBoxen wieder genommen.

    Bei der Variante von tko hab ich nix weiteres mehr gefunden um das Problem mit dem ruckelnden ball zu beheben.

    Damit sich die pictureBoxen mit dem Hintergrundbild vertragen muss man folgendes tun:

    Man muss die BackgroundImage-Eigenschaft der Form überschreiben.
    Dazu erstellt man sich eine Property für das BackgroundImage.

    Die get-Methode liefert einen Bitmap-Typen zurück, und in der set-Methode zeichnet man dann das Image sozusagen ins vordefinierte Bitmap wider hinein.

    Das vordefinierte Bitmap muss dabei den Wert PixelFormat::Format32bppPArgb besitzen sonst geht nix.

    Das ganze sollte ungefähr so aussehen:

    private:
    	Bitmap^ bitmap;
    
    	public:
    		property Image^ BackgroundImage
    		{
    			virtual Image^ BackgroundImage::get () override
    			{
    				return bitmap;
    			}
    
    			virtual void BackgroundImage::set (Image^ wert) override
    			{
    				 bitmap = gcnew Bitmap (Width, Height, System::Drawing::Imaging::PixelFormat::Format32bppPArgb);
    				 Graphics^ g = Graphics::FromImage (bitmap);
    
    			 	 Image^ mainBild = wert;
    				 g->DrawImage (mainBild, 0, 0, Width, Height);
    			}
    		}
    

    gruß



  • Hm überleg mal was du schreibst jede millisekunde den timer ist ziemlich übertrieben und würde 1000 mal pro sekunde ausgelöst werden wenn es tatsächlich so funktionieren würde.



  • Wieso sollte es übertrieben sein den Timer auf 1 ms zu stellen ? weis nicht genau was du meinst aber lass das programm mal ohne und mal mit property laufen. Wirst den Unterschied dann sehen...

    #pragma once
    
    namespace test 
    {
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	public ref class Form1 : public System::Windows::Forms::Form
    	{
    	private:
    		int xPosition, yPosition;
    		int xSpeed, ySpeed;
    		Bitmap^ bitmap;
    
    	/*public:
    		property Image^ BackgroundImage
    		{
    			virtual Image^ BackgroundImage::get () override
    			{
    				return bitmap;
    			}
    
    			virtual void BackgroundImage::set (Image^ wert) override
    			{
    				bitmap = gcnew Bitmap (Width, Height, Imaging::PixelFormat::Format32bppPArgb);
    				Graphics^ g = Graphics::FromImage (bitmap);
    
    			 	Image^ mainBild = wert;
    				g->DrawImage (mainBild, 0, 0, Width, Height);
    			}
    		} */
    
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    			//
    			//TODO: Konstruktorcode hier hinzufügen.
    			//
    			xPosition = pictureBox1->Location.X;
    			yPosition = pictureBox1->Location.Y;
    			xSpeed = 5;
    			ySpeed = 5;
    
    			this->BackgroundImageLayout = ImageLayout::Stretch;
    		}
    
    	protected:
    		~Form1()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    
    	private: System::Windows::Forms::PictureBox^  pictureBox1;
    	private: System::Windows::Forms::Timer^  timer1;
    
    	private: System::ComponentModel::IContainer^  components;
    
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Erforderliche Methode für die Designerunterstützung.
    		/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			this->components = (gcnew System::ComponentModel::Container());
    			System::ComponentModel::ComponentResourceManager^  resources = (gcnew System::ComponentModel::ComponentResourceManager(Form1::typeid));
    			this->pictureBox1 = (gcnew System::Windows::Forms::PictureBox());
    			this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
    			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->pictureBox1))->BeginInit();
    			this->SuspendLayout();
    			// 
    			// pictureBox1
    			// 
    			this->pictureBox1->BackColor = System::Drawing::Color::Transparent;
    			this->pictureBox1->BackgroundImageLayout = System::Windows::Forms::ImageLayout::None;
    			this->pictureBox1->Image = (cli::safe_cast<System::Drawing::Image^  >(resources->GetObject(L"pictureBox1.Image")));
    			this->pictureBox1->Location = System::Drawing::Point(306, 213);
    			this->pictureBox1->Name = L"pictureBox1";
    			this->pictureBox1->Size = System::Drawing::Size(20, 20);
    			this->pictureBox1->TabIndex = 0;
    			this->pictureBox1->TabStop = false;
    			// 
    			// timer1
    			// 
    			this->timer1->Enabled = true;
    			this->timer1->Interval = 1;
    			this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
    			// 
    			// Form1
    			// 
    			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
    			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    			this->BackgroundImage = (cli::safe_cast<System::Drawing::Image^  >(resources->GetObject(L"$this.BackgroundImage")));
    			this->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch;
    			this->ClientSize = System::Drawing::Size(632, 446);
    			this->Controls->Add(this->pictureBox1);
    			this->ForeColor = System::Drawing::Color::Transparent;
    			this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedSingle;
    			this->Name = L"Form1";
    			this->Text = L"Form1";
    			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->pictureBox1))->EndInit();
    			this->ResumeLayout(false);
    
    		}
    #pragma endregion
    
    	private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) 
    			 {
    				 xPosition = xPosition + xSpeed;
    				 yPosition = yPosition + ySpeed;
    
    				 pictureBox1->SetBounds (xPosition, yPosition, pictureBox1->Width, pictureBox1->Height);	
    
    				 //Kollisionserkennung
    				 if (pictureBox1->Location.Y >= this->Height-50)
    					ySpeed = -ySpeed;
    
    				 if (pictureBox1->Location.Y <= 0)
    					 ySpeed = -ySpeed;
    
    				 if (pictureBox1->Location.X + pictureBox1->Width >= this->Width - 5)
    					 xSpeed = -xSpeed;
    
    				 if (pictureBox1->Location.X <= 0)
    					 xSpeed = -xSpeed;
    			 }
    	};
    }
    


  • Wieso sollte es übertrieben sein den Timer auf 1 ms zu stellen ?

    Die Auslösung der Timer gibt alleine schon keine 1ms her.

    Die Zeitgeberkomponente in Windows Forms ist Singlethreaded und auf eine Genauigkeit von 55 Millisekunden beschränkt. Wenn Sie einen Multithread-Zeitgeber mit größerer Genauigkeit benötigen, verwenden Sie die Timer-Klasse im System.Timers-Namespace.


Anmelden zum Antworten