Laden...

Game Projekt: "Superball"

Erstellt von SexyEnemy vor 19 Jahren Letzter Beitrag vor 19 Jahren 14.071 Views
S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren
Game Projekt: "Superball"

hallöchen zusammen.

ich habe mir mal vorgenommen ein kleines einfaches level für das tolle Spiel, was immer im frühstücksfernsehen kam, "Superball", mit c# zu programmieren.

Falls jemand der name Superball nichts sagt: es ist folgendes spiel:
ein spiel was immer im frühstücksfernsehen kam, wo man mit dem telefon einen ball nach rechts und links bewegen muss um hindernisse zu umgehen.

Nun die Fage. wo fange ich da am besten an...bzw was brauche ich im endefekt alles.

Kann mir einer ein paar tipps geben?

bye bye 😉


Mess with the best die like the rest!


X
2.051 Beiträge seit 2004
vor 19 Jahren

Original von SexyEnemy
Nun die Fage. wo fange ich da am besten an...bzw was brauche ich im endefekt alles.

Auf jedenfall einen Telefonanschluß besorgen. 😁
Und jemanden, der auch mit spielt. 8o

aber im ernst, was kannst du denn so alles?
dass du SDK, Computer, Zeit, etc. hast, versteht sich von alleine

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

lol...hehe

also für das erste ist schon mal gesorgt...aber ichg laube meine tastatur tut es auch 😉

naja und spielen...man spielt ja eh nur selber und nicht zu zweit 😉


Mess with the best die like the rest!


M
456 Beiträge seit 2004
vor 19 Jahren

Hallo,

ich würd das so machen:
Am Anfang schreib ich mir ne einfache Gameloop, die immer wieder dein Spielfeld zeichnet und am Ende einen Pageflip durchführt. (Siehe DX Tutorial hier im Forum)
Mit DirectInput kannst du die Tastatur abfragen. Je nachdem welche Taste du gedrückt hast, würde ich die x-Koordinate deiner Kugel bei jedem Frame inkrementieren bzw. dekremtieren.
Um flüssige Bewegungen zu erzeugen, musst du deine Objekte mit Hilfe der Zeitdifferenz des jeweiligen Frames verschieben.
Die anderen Kugeln, die dir entgegen kommen, würde ich mit einer Zufallszahlen für ihren Startpunkt initialisieren. Und auch hier inkrementierst du die y-Koordinate deiner Objekte bei jedem neuem Frame zeitabhängig.
Ob sich zwei Kugeln treffen, kannst du mit dem Satz des Pythagoras berechen.
Abstand = sqrt( x2 + y2 ). Ist der Abstand kleiner als der Radius beider Kugeln, so liegt eine Kollision vor.

Ich hoffe ich konnte dir ein paar Anreize geben.

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

Also ich habe jetzt mal einen "ball" und ne grundfläche, die aber noch skaliert und transformiert wird erstellt.

ich wollte nun eine textur auf den ball legen, aber irgendwas habe ich wohl vergessen,

hab eine textur erstellt, doch dann sind meine 3d elemente nur noch schwarz?

ich habe mal den code online gestellt.
vll kann mir einer helfen.

Ach ja, und wie kriege ich die sphäre, welche in Mesh enthalten ist richtig rund machen, da sie so komisch oval ist. habe alle variablen versucht zu ändern, aber es tut sich nix.

Dann hab ich nioch ein problem, und zwar: wenn ich die fenstergröße um 100 kleiner mache, dann sieht man nichts mehr von den figuren...woran liegt es?

ist der view point falsch?

Hier ist mein bisheriger code:
http://www.binchen-online.de/superball.htm

vielen lieben danke

LG: sexyenemy


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Oft gemachter Fehler: Integerdivision. Du berechnest die aspect ratio, indem du Width durch Height teilst. Beides sind int-Werte. Wenn Width < Height ist das Ergebnis gleich 0. Wenn es größer ist, ist es 1 (oder 2, 3, 4 etc.). Daher bekommst du immer Eier-Bälle oder (bei 0) nichts mehr zu sehen. Ändere die Zeile mit der Projection Matrix wie folgt


device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, (float)ClientSize.Width / ClientSize.Height, 1.0f, 100.0f );

Wichtig ist der float cast minimal einer der beiden Werte (Width oder Height). Dadurch geschieht die Division so, wie du es erwartest. Übrigens benutze ich hier ClientSize, da das die tatsächliche Anzeigefläche für D3D ist.

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

Cool, dankeschön

jetzt klappt das auch mit der Fenstergröße..super

Aber ich trotzalledem kriege ich immernoch nicht meine Textur auf meine Kugel.
in den Beispielen und Tutorials seh ich das textures immer nur im Zusammenhang mit einem vertex buffer...allerdings muss das doch auch ohne gehen...

bei mir sieht man aber nur noch schwarz...sozusagen...

woran liegt das?

LG: SE


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Das liegt daran, dass die Prefab Methoden von Mesh keine Texturkoordinaten erzeugen.
Du müsstest wie folgt vorgehen:

  1. Mesh clonen mit einem Vertex-Format, dass Texturkoordinaten enthält

// format mit position, normale und einem textureset
VertexFormats format = VertexFormats.PositionNormal | VertexFormats.Texture1;
box = Mesh.Box( device, 2.0f, 10.0f, 5.0f );//Höhe | Länge | Breite
Mesh tempBox = box.Clone( box.Options.Value, format, device );
// das alte Mesh wird nicht mehr benötigt
box.Dispose();
// referenz anpassen
box = tempBox;

  1. Die Texturkoordinaten selbst schreiben

// locken
Vertex[] verts = (Vertex[])box.VertexBuffer.Lock( 0, typeof( Vertex ), LockFlags.None, box.NumberVertices );
// schreiben
for ( int i = 0; i < verts.Length; ++i ) {
    // Koordinaten berechnen
    verts[i].Tu = /*...*/;
    verts[i].Tv = /*...*/;
}
// lock aufheben
box.VertexBuffer.Unlock();

Fertig!

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

sehe ich das richtig, dass dein vorschlag nur mit einem vertex buffer funzt?

und warum erkennt er Vertex[] nicht?
muss ich da noch ein assembly implementieren?

und wie soll ich denn die vertices berechnen?

man ich bin einfach zu blöd 😦(


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Oh Entschuldigung, Vertex hatte ich per using abgekürzt:


using Vertex = CustomVertex.PositionNormalTextured;

Liest sich einfach besser 😁

Du musst lediglich die Texturkoordinaten einfüllen. Natürlich musst du dir die selbst überlegen, denn die Objekte könnten auf verschiedenste Art und Weise texturiert sein.
(0/0) ist die Ecke links oben, (1/1) ist die Ecke rechts unten.

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

der schluckt das using... nicht

CustonVertex kennt er nicht


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Sorry, wieder mein Fehler 😁

using Vertex = Microsoft.DirectX.Direct3D.CustomVertex.PositionNormalTextured;

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

ui ui ui, das wird wird ja immer bunter hier

also erstmal meckert der compiler nicht mehr rum 😉

ne textur ist immernoch nicht zu sehen, aber als ich die vertex punkte mal auf 0 gesetzt habe bei deinem code passiert a was schreckliches

daraus wird dann das hier:

Hilfe, das wird ja immer schlimmer 😮


Mess with the best die like the rest!


S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

sorry, diesmal war es mein fehler

da ich die textur ja auch meine kugel legen will, hab ich vergessen bei dem zweiten teil des codes die box zu ändern 😉

hab also wieder mein ausgangsbild, aber noch keine Textur 😦(

aktueller code liegt wie immer unter

http://www.binchen-online.de/superball.htm


Mess with the best die like the rest!


S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

Ach ja...

ich habe schon einmal nen KeypressEventhandler eingebaut

wenn ich ihn als eigene klasse mache funktioniert er fantastisch,
nur sobald ich ihn in meinen code einbaue, bricht mein ganzes programm zusammen und setzt auch noch meine cpu auslasten bis zum rand voll auf 100%.

woran das aber schon wieder liegt weiß ich nicht, da der keyhandler an sich ja super funzt.

na guti...werd dann auch mal ins bett

Bis morgen

Nachti


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Du kannst natürlich nicht einfach alle Texturkoordinaten auf (5,3) setzen, sondern musst sie je nach Punkt verschieden berechnen. Zu Testzwecken könntest du das z.B. so machen:


for ( int i = 0; i < verts.Length; ++i ) {
  verts[i].Tu = verts[i].X;
  verts[i].Tv = verts[i].Y;
}

Übrigens waren einige kleine Fehler im Code. In OnDeviceResizing: Nach dem


 texture = TextureLoader.FromFile(device, "D:\\C#\\superball\\superball\\smiley.bmp");

fehlt noch ein


device.SetTexture( 0, texture );

Dafür kann dies weg (in initializeGraphics):


if ( bmp != null ) texture = Texture.FromBitmap( device, bmp, 0, Pool.Managed );

device.SetTexture( 0, texture );

Dass sich der KeyHandler das Programm aufhängt liegt an der MessageBox im Verband mit der Gameloop. Die gameloop sollte entweder aussetzen, wenn die MessageBox angezeigt wird, oder du solltest eine andere Art gameloop benutzen.
Zum Aussetzen ginge so etwas:


bool showMB = false;

public void OnKeyPress(object sender, KeyEventArgs e) {
    showMB = true;
    MessageBox.Show( this, e.KeyCode.ToString(), "Your input" );
    showMB = false;
    Invalidate();
}

private void OnPaint(object sender, PaintEventArgs e) {
//...
    if ( !showMB ) {
        this.Invalidate();
    }
}

Auf diese Weise wird nur ein neues Frame gezeichnet, wenn die Messagebox nicht angezeigt wird.

MfG VizOne

H
704 Beiträge seit 2003
vor 19 Jahren

da es hier jetzt um Direct3D geht, verschiebe ich das jetz mal ins DirectX Foum...

[last.fm](http://www.last.fm/user/hauptmanAlpha/)
S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

ich habe mal den teil mit der textur nen bisschen abgewandelt mit materielvon meinem dozenten

die textur ist nun zu sehen aber nun ist meine kugel zu der form geworden die mein dozent in seinem code hat

wie bekomme ich jetzt aus dem ganzen wirrwar der zahlen meine kugel zurück 😮

	Vertex[] verts = (Vertex[])sph.VertexBuffer.Lock( 0, typeof( Vertex ), LockFlags.None, sph.NumberVertices );  
	// schreiben  
	  
	float arcus_increment = (float)(2.0 * Math.PI / (verts.Length-2)); //cylinder angular increment  
	float    tu_increment = (float)(3.0           / (verts.Length-2)); //1.0 Anzahl der Bilder horizontal  
	Vector3 v = new Vector3();  
	for (int i = 0; i &lt; verts.Length; i++) {  
		float arcus = i * arcus_increment;  
		v.X = (float)Math.Cos( arcus );  
		v.Y = (float)Math.Sin( arcus );  
		if ( i%2 == 0 ) v.Z =  1.0f;  
		else            v.Z = -1.0f; //zigzag between top and bottom  
		verts_.Position = v; //vertex = (cos,sin,+1) or (cos,sin,-1)  
		v.Z =  0;           //cylinder normals have no Z-component  
		verts_.Normal   = v; //normal = (cos,sin,0)   
		  
		verts_.Tu = i * tu_increment; //horizontal texture position  
		if ( i%2 == 0 ) verts_.Tv = 0.0f;  
		else            verts_.Tv = 1.0f; //1.0 vertical zigzag on texture image //anzahl der Reihen der Bilder vertikal  
	}

Mess with the best die like the rest!


S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

juchu...ich habe es irgendwie mit der textur hinbekommen, aber so richtig die feine art ist das bestimmt nicht
Meine tastaturabfragen funktionieren auch schon mal hervorragend

Was müsste ich nun tun, um verschiedene texturen auf verschieden figuren anzuwenden?

hier mein bisheriges ergebnis

und der aktuelle quellcode

MfG: SE


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Vor dem Rendern eines Meshes die Textur neu setzen (SetTextur).

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

ja das mit setTexture ist klar, nur ich möchte ja verschiedene texturen setzen.

bei den kugeln habe ich es hinbekommen, wie auf dem bild bei der letzten antwort zu sehen ist.

Aber mein Untergund(box) will nicht so richtig eine textur annehmen.

PS: kann man ein Hintergundimage in das fenster legen?

aktueller code wie immer unter: quellcode

mfg: SE


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Einen Hintergrund kann man am besten zeichnen, indem man auf ein Viereck aus zwei Dreiecken eine Textur legt und dieses mit ausgeschaltetem ZBuffer und mit orthogonaler Projektion vor allem anderen rendert.

Da ich gerade Langeweile hatte, habe ich eine Klasse geschrieben, die das übernimmt.


#region Using directives

using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

// Ein Vertex des Hintergrundes
using Vertex = Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured;

#endregion


namespace SuperBall {

  /// <summary>
  /// Rendert eine Textur als Bildhintergrund
  /// </summary>
  public class BackgroundImage : IDisposable {

    private VertexBuffer m_vb;
    private Texture m_texture;
    private Device m_device;
    private StateBlock m_currentStates;

    /// <summary>
    /// Konstruktor
    /// </summary>
    /// <param name="device">Das renderdevice. Darf nicht null sein.</param>
    /// <param name="imageFile">Name des Hintergrundbildes</param>
    public BackgroundImage(Device device, string imageFile) {

      // argumente überprüfen
      if ( device == null ) {
        throw new ArgumentNullException( "device" );
      }
      if ( imageFile == null ) {
        throw new ArgumentNullException( "imageFile" );
      }

      // vertexbuffer erzeugen...
      m_vb = new VertexBuffer( typeof( Vertex ), 4, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Texture1, Pool.Managed );
      // ... und füllen
      Vertex[] verts = (Vertex[])m_vb.Lock( 0, LockFlags.NoSystemLock );
      verts[0] = new Vertex( -1, 1, 1, 0, 0 );
      verts[1] = new Vertex( 1, 1, 1, 1, 0 );
      verts[2] = new Vertex( -1, -1, 1, 0, 1 );
      verts[3] = new Vertex( 1, -1, 1, 1, 1 );
      m_vb.Unlock();

      // textur laden
      m_texture = TextureLoader.FromFile( device, imageFile );
      m_device = device;

      // state-block erstellen
      CreateStateBlock();

      // auf ein reset reagieren (um den stateblock neu zu erstellen)
      m_device.DeviceReset += new EventHandler( HandleDeviceReset );
    }


    /// <summary>
    /// Rendert das Hintergrundbild
    /// </summary>
    /// <remarks>
    /// Nach Ablauf der Methode befindet sich das Device in dem gleichen Zustand
    /// wie zuvor.
    /// </remarks>
    public void Render() {
      // aktuelle Einstellungen speichern
      m_currentStates.Capture();
      try {
        // Einstellungen setzen
        SetStates();
        // Objekt rendern
        m_device.DrawPrimitives( PrimitiveType.TriangleStrip, 0, 2 );

      } finally {
        // alte Einstellungen zurücksetzen
        m_currentStates.Apply();
      }
    }

    /// <summary>
    /// Befreit nicht mehr benötigte Resourcen
    /// </summary>
    /// <remarks>
    ///   Sobald das Objekt nicht mehr benutzt wird, sollte
    ///   diese Methode aufgerufen werden.
    /// </remarks>
    public void Dispose() {

      // aufräumen...
      if ( m_texture != null ) {
        m_texture.Dispose();
        m_texture = null;
      }

      if ( m_vb != null ) {
        m_vb.Dispose();
        m_vb = null;
      }

      if ( m_currentStates != null ) {
        m_currentStates.Dispose();
        m_currentStates = null;
      }

      m_device = null;
    }

    private void SetStates() {
      // alle Einstellungen setzen...

      // vertex buffer
      m_device.SetStreamSource( 0, m_vb, 0, Vertex.StrideSize );
      m_device.SetStreamSource( 1, null, 0 );
      m_device.VertexFormat = Vertex.Format;

      // textur
      m_device.SetTexture( 0, m_texture );

      // render states
      m_device.RenderState.Lighting = false;
      m_device.RenderState.ZBufferEnable = false;
      m_device.SamplerState[0].MagFilter = TextureFilter.Linear;
      m_device.SamplerState[0].MinFilter = TextureFilter.Linear;

      // Transformationsmatrizen setzen
      Matrix proj = Matrix.OrthoLH( 2.0f, 2.0f, 0.1f, 2.0f );
      Matrix worldView = Matrix.Identity;
      m_device.SetTransform( TransformType.World, worldView );
      m_device.SetTransform( TransformType.View, worldView );
      m_device.SetTransform( TransformType.Projection, proj );
    }

    private void CreateStateBlock() {
      // evtl. erst aufräumen
      if ( m_currentStates != null ) {
        m_currentStates.Dispose();
        m_currentStates = null;
      }

      // aufzeichnen eines stateblocks einleiten
      m_device.BeginStateBlock();
      // states für dieses objekt setzen
      // hierdurch wird bestimmt, was der stateblock später
      // aufzeichnen wird
      SetStates();
      // fertig :)
      m_currentStates = m_device.EndStateBlock();
    }




    void HandleDeviceReset(object sender, EventArgs e) {
      // das device wurde zurückgesetzt - stateblock neu erstellen
      CreateStateBlock();
    }
  }
}


Die Benutzung ist sehr einfach. Einfach eine Membervariable erstellen


using SuperBall;
//...

public class Form1 : Form {
// ...
  BackgroundImage background;

//...
}

In InitializeGraphics (nachdem das Device erstellt wurde):


background = new BackgroundImage( device, "hintergrund.bmp" );

Und in OnPaint direkt(!) nach dem BeginScene:


background.Render();

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

der erkennt den namespace nicht 🙁


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Welchen?

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

habe jetzt das daraus gemacht: SuperBall.SuperBall.BackgroundImage

beim starten kommt jedoch eine SystemArgumentnullException...was heißt das?


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

a) Du solltest die Klasse, die ich dir gegeben habe besser in eine eigene Datei kopieren - das ist übersichtlicher und dann klappt's auch mit dem namespace (denke ich)

b) Du darfst BackgroundImage erst erstellen, nachdem du das Device erstellt hast (z.B. ganz am Ende von InitializeGraphics)

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

hab es ja als extra klasse im projekt

aber etzt funzt es...das mit dem device war das problem

Danke die klasse ist supergeil...


habe jetzt einen Timer eingebaut, der die Highscore alle 3 sekunden hochzählen soll.
die score erhöhrt er ohne probleme, aber wie aktualisiere ich jetzt mein Textmesh?

In InitializeGraphics:

meshScore = Mesh.TextFromFont(device, new System.Drawing.Font("Arial", 8), scoreString, 10f, 0);


private void Timer1_Elapsed(object sender, ElapsedEventArgs e) {
score ++;
scoreString = "Score: " + Convert.ToString(score);
MessageBox.Show("Score: "+scoreString, "Timer Event Raised!");
}


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

z.B. so:


private void Timer1_Elapsed(object sender, ElapsedEventArgs e) {
  score ++;
  scoreString = "Score: " + Convert.ToString(score);
  if(meshScore != null) {
    meshScore.Dispose();
  }

  meshScore = Mesh.TextFromFont(device, new System.Drawing.Font("Arial", 8), scoreString, 10f, 0);

//MessageBox.Show("Score: "+scoreString, "Timer Event Raised!");
}

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

also egal was und wie ich es mache, der wirft immer ne NullReferenceException an der stelle:

object reference not set to ......

meshScore = Mesh.TextFromFont(device, new System.Drawing.Font("Arial", 8), scoreString, 10f, 0);


Mess with the best die like the rest!


1.373 Beiträge seit 2004
vor 19 Jahren

Lad nochmal den aktuellen Code hoch.

MfG VizOne

S
SexyEnemy Themenstarter:in
23 Beiträge seit 2004
vor 19 Jahren

ok is oben, so wie er jetzt ist mit der exception

HIER


Mess with the best die like the rest!