# Betatester für BombSweety gesucht!



## Apo (20. Aug 2006)

Hi,

ich habe ein kleines Spiel geschrieben, um mir Java etwas näherzubringen. 
Es wird JAVA 1.5 benötigt, weil ich einige Funktionen aus 1.5 benutze.

Worum geht es?
Ganz einfach Sweety mit Hilfe von Bomben in den Zielbereich "zu schießen". Großes Vorbild war PuffBomb.
Ein Editor zum einfachen Erstellen von neuen Levels ist auch schon dabei.

Steuerung:
Beim Spiel einfach auf eine Bombe drücken im Hud, dann kommt sie ins Spielfeld. Dort wieder anklicken und dorthin verschieben, wo sie explodieren soll. Dann noch im Hud die Zeit mithilfe des Reglers einstellen, wann die Bombe hochgehen soll. Mit den Pfeiltasten kann man eine Bombe die ausgewählt ist Pixelweise verschieben. Dann entweder Enter drücken oder auf den PlayButton drücken und schauen, ob die Bombe es schafft Sweety ins Ziel zu befördern.

Ein Screenshot seht ihr hier !

Downloaden könnt ihr die Exe hier !
Falls ihr lieber die Jar mit den Source-Codes haben wollt dann hier !


Ich habe aber noch einige Fragen dazu:

Wenn eine Bombe explodiert bekommt Sweety natürlich eine neue Geschwindigkeit in x und y Richtung.
Ich habe es zur Zeit mehr oder weniger mit dem Abstand der Bombe zu Sweety geregelt und berechne dadurch die neuen Geschwindigkeiten. Aber so richtig glücklich macht mich diese Lösung nicht. Hat jemand eine Idee, wie man die neuen Geschwindigkeiten berechnen könnte. Theoretisch weiß ich auch wie Sweety fliegen müsste, kann bloss keinen Algorithmus davon ableiten.

Edit: 2tes Problem schon gelöst 


Ich danke schonmal,
MfG Apo


----------



## foobar (20. Aug 2006)

Wow, sieht super aus  :applaus: 

Aber warum gibt es das Spiel nur in Form einer Exe?


----------



## Apo (20. Aug 2006)

och eigentlich nur so,
habe jetzt auch die Jar-Datei online gestellt, falls die lieber gewollt ist. Habe ja nichts zu verstecken. 
Klich mich!


----------



## foobar (20. Aug 2006)

Ein paar Anmerkungen:
- Beim Klick auf Optionen tut sich nichts.
- Es wäre schön, wenn man im Spiel sehen könnte in welchem Level man sich gerade befindet.
- Es wäre nett, wenn man den aktuellen Spielstand speichern könnte um dann später an der selber Stelle weiter machen zu können.
- Manchmal hängt das Spiel, wenn Sweety aus dem Spielrahmen fliegt und dann von oben wieder runter kommt.  Ichn konnte das bisher aber nicht reproduzieren.


----------



## foobar (20. Aug 2006)

Hab mal die jar-Version unter Linux getestet:
- Das Programm erscheint in einem riesigen Frame, dessen Ausmaße meine Auflösung von 1600 x 1200 bei weitem überfordern. In der Linken oberen Ecke kann man das eigentliche Panel erkennen.

- Bei einem Klick auf Game fliegt folge Exception:

```
Exception in thread "main" java.lang.UnsupportedOperationException: Cannot change display mode
        at java.awt.GraphicsDevice.setDisplayMode(GraphicsDevice.java:259)
        at bomb.bombMain.<init>(bombMain.java:100)
        at bomb.bombMain.main(bombMain.java:256)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at bomb.bombPanelGameGround.paintComponent(bombPanelGameGround.java:663)
        at javax.swing.JComponent.paint(JComponent.java:1005)
        at javax.swing.JComponent.paintChildren(JComponent.java:842)
        at javax.swing.JComponent.paint(JComponent.java:1014)
        at javax.swing.JComponent.paintWithOffscreenBuffer(JComponent.java:4963)
        at javax.swing.JComponent.paintDoubleBuffered(JComponent.java:4916)
        at javax.swing.JComponent._paintImmediately(JComponent.java:4859)
        at javax.swing.JComponent.paintImmediately(JComponent.java:4666)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:451)
        at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:114)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
        at java.awt.EventD
```

Stellst du den Source auch zur Verfügung, dann finde ich bestimmt noch mehr Dinge die man verbessern kann ;-)

BTW Klassen sollten immer mit einem Großbuchstaben beginnen.


----------



## Campino (20. Aug 2006)

mhh...die neue x/y-Richtung abhängig von der Entfernung der Bombe ist ein Vektor. Du addierst einfach die bisherige Bewegung zu der neuen und hast eine Physikalisch halbwegs korrekte Bewegung...(du ignorierst Reibung u.ä.). 
Beispiel: 
Das Ding bewegt sich mit 1 in x-Richtung und 2 in y-Richtung (1/2). Die nächste Bombe ändert die Richtung nach (-1/3). (1/2)+(-1/3)=(1+-1/2+3)=(0/5)

Falls ich dein Problem richtig verstanden habe, sollte das so gehen...

EDIT: 
Zur Vektorrechnung siehe Beni's Tutorial: http://www.java-forum.org/de/viewtopic.php?t=7220


----------



## André Uhres (20. Aug 2006)

Das Spiel funzt tadellos unter Windows XP. 
Sehr lustiges und geniales Spiel   :applaus:    :toll:


----------



## Apo (20. Aug 2006)

Erstmal großes thx für das ausprobieren und die schnelle Berichterstattung.

Das mit den Options ist richtig. Das wird noch gemacht (da soll später eingestellt werden können, ob Fullscreen oder Window und ob Sounds an oder nicht ...)

Die Anzeige mit den Levels habe ich schnell eingefügt.

Das mit dem Speichern, wie weit man ist, überlege ich grad, wie es sinnvoll ist.
Ich habe nun erstmal 2 Buttons hinzugefügt, durch die man einfach das Level, was man möchte, anwählen kann.

Das mit dem Absturz bzw Hacken .... ich weiß nicht woran das liegen könnte.


btw.: habe die neue Version hochgeladen mit Source Code (aber gleich eine Vorwarnung ... er ist noch KOMPLETT unkommentiert und außerdem ist er von mir ... also erwartet kein Meisterwerk  ) 
Klick mich


----------



## kaie (20. Aug 2006)

Bezüglich der Rotation von Sweety:

Kopiere vor dem Erstellen der Rotationstransformation die vorherige Transformation:

```
AffineTransform kopie = (AffineTransform)g.getTransform().clone();
```
Dann kannst Du nach dem Zeichnen der gedrehten Figur einfach die alte Transformation wieder herstellen:

```
g.setTransform(kopie);
```


----------



## Apo (20. Aug 2006)

ahh danke der Rotationstipp funktioniert!!!
Big thx!!!
ist jetzt in der neuen Version drin (also mit Sweetyrotation ... sieht dadurch noch lustiger aus  )

das mit dem Speed probiere ich auch nochmal irgendwie hinzubekommen
aber habe noch nicht so richtig die Idee
ich werde mir die Vektorensache nochmal durchlesen ...


----------



## foobar (20. Aug 2006)

So ich hab das Spiel jetzt auch unter Linux zum laufen bekommen. Folgende Änderungen habe ich vorgenommen:


```
package bomb;

import java.awt.*;
import java.io.File;
import java.util.Vector;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BombMain extends JFrame
{

	private static final long 			serialVersionUID = 1L;
	
	private final JFileChooser			fc = new JFileChooser();
	private final BombClassFileFilter	cff = new BombClassFileFilter();
	
	private GraphicsDevice 				myDevice;
	private DisplayMode 				oldDisplayMode;
	
	private BombPanelGame				bPG;
	private BombPanelEditor				bPE;
	private BombPanelMenu				bPM;
	
	private static BombKey				bK;
	
	private BombLevel					bLGame, bLEditor;

	private String						sCurrentDirectory;
	
	private JPanel						contentPanel;
	
	private boolean						bFirst;

	public BombMain()
	{
		super();
		
		this.setTitle( "=== BombSweety ===" );
		
		this.setLayout(new BorderLayout());
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		this.bPG		= new BombPanelGame( this );
		this.bPE		= new BombPanelEditor( this );
		this.bPM		= new BombPanelMenu( this );
		
		this.contentPanel	= this.bPM;
		
		bK				= new BombKey( this.bPG.getbPGG() );
		this.addKeyListener( bK );
		
		this.add( this.contentPanel );
		
		this.bLGame			= new BombLevel( this.bPE.getiWall(), this.bPE.getiBrick(), this.bPE.getiBrickExplode(), this.bPE.getiSweetyNormal(), this.bPE.getiSweetyTime(), this.bPE.getiSweetyExplode() );
		this.setLoadFirstLevel();
		
		this.bLEditor		= new BombLevel( this.bPE.getiWall(), this.bPE.getiBrick(), this.bPE.getiBrickExplode(), this.bPE.getiSweetyNormal(), this.bPE.getiSweetyTime(), this.bPE.getiSweetyExplode() );
		this.bLEditor.setEmptyLevel();
		this.bPE.load( -1 );
		this.bPE.setBombLevelHud( this.bLEditor );
		
		this.sCurrentDirectory		= "";
        
		this.bFirst					= true;
		
		BombImage AFI	= new BombImage( this );
		setIconImage( AFI.setPicsMain( "/images/Icon.gif", false ) );
		
		GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice[] myDevice = env.getScreenDevices();
		
		this.myDevice  = myDevice[0];
		this.oldDisplayMode = this.myDevice.getDisplayMode();
		
		DisplayMode newDisplayMode = new DisplayMode( 640, 480, oldDisplayMode.getBitDepth(), oldDisplayMode.getRefreshRate());
		
		boolean bFullScreenSupported = this.myDevice.isFullScreenSupported();
		
		this.setUndecorated(bFullScreenSupported);
		this.setResizable(!bFullScreenSupported);
		
		if ( !bFullScreenSupported  && this.myDevice.isDisplayChangeSupported())
		{
			this.myDevice.setFullScreenWindow( this );
		    this.myDevice.setDisplayMode( newDisplayMode );
		} else
		{
			this.myDevice.setFullScreenWindow(null);
			this.setUndecorated( false );
			this.setResizable( false ); // das Frame wird nicht grössenveränderbar sein vom user
		}
		
        pack();
        setLocationRelativeTo(null);
		setVisible(true); // setzt das Fenster auf sichtbar*/
	}

	public void setFullscreen( boolean bFullscreen )
	{
		DisplayMode newDisplayMode = new DisplayMode( 640, 480, oldDisplayMode.getBitDepth(), oldDisplayMode.getRefreshRate());
		if ( bFullscreen )
		{
		    this.dispose();
			this.setUndecorated( true );
			this.myDevice.setFullScreenWindow( this );
		    this.myDevice.setDisplayMode( newDisplayMode );
		    this.setVisible( true );
		} 
        else
		{
			this.myDevice.setFullScreenWindow(null);
			this.dispose();
			this.setUndecorated( false );
			this.setLocation( this.oldDisplayMode.getWidth()/2 - 320, this.oldDisplayMode.getHeight()/2 - 240);
			this.pack();
			this.setVisible( true );
		}
	}
	
	public void setGame()
	{
		remove(contentPanel);
		contentPanel	= bPG;
        //this.addKeyListener( this.bK );
		add(BorderLayout.CENTER, contentPanel);
		validate();
		contentPanel.repaint();
	}
	
	public void setEditor()
	{
		super.remove(this.contentPanel);
		this.contentPanel	= this.bPE;
		if ( this.bFirst )
		{
			this.bFirst		= false;
		}
		//this.removeKeyListener( this.bK );
		super.add(this.contentPanel);
		super.validate();
		this.contentPanel.repaint();
	}
	
	public void setMenu()
	{
		super.remove(this.contentPanel);
		this.contentPanel	= this.bPM;
		//this.removeKeyListener( this.bK );
		super.add(this.contentPanel);
		super.validate();
		this.contentPanel.repaint();
	}
	
	public void save( Vector vWall, Vector vBrick, Vector vSweety, Vector vFinish, int bombCount, String name, int level )
	{
		this.fc.setFileFilter( this.cff );
        if ( sCurrentDirectory.length() < 1 ) {
            sCurrentDirectory = System.getProperty("user.dir") + "";
            fc.setCurrentDirectory(new File( this.sCurrentDirectory ));
        }
        int p = fc.showSaveDialog(this);
        if(p == 0)
        {
            String s = fc.getSelectedFile().getPath();
            int t = s.indexOf(46);
            if ( t != -1 )
            {
            	s	= s.substring( 0, t );
            }
            s	+= ".bomb";
            BombWall[] aWall	= new BombWall[ vWall.size() ];
            for ( int i = 0; i < aWall.length; i++ )
            {
            	aWall[i]	= (BombWall)(vWall.get( i ));
            }
            BombSweety[] aSweety	= new BombSweety[ vSweety.size() ];
            for ( int i = 0; i < aSweety.length; i++ )
            {
            	aSweety[i]	= (BombSweety)(vSweety.get( i ));
            }
            BombFinish[] aFinish	= new BombFinish[ vFinish.size() ];
            for ( int i = 0; i < aFinish.length; i++ )
            {
            	aFinish[i]	= (BombFinish)(vFinish.get( i ));
            }
            this.bLEditor.setAll( vWall, vBrick, vSweety, vFinish, bombCount, name, level );
            this.bLEditor.writeLevel( s );
            //System.out.println("s = "+s);
        }
	}
	
	public void load( boolean bEditor )
	{
		this.fc.setFileFilter( this.cff );
        if ( sCurrentDirectory.length() < 1 ) {
            sCurrentDirectory = System.getProperty("user.dir") + "";
            fc.setCurrentDirectory(new File( this.sCurrentDirectory ));
        }
        int p = fc.showOpenDialog(this);
        if(p == 0)
        {
            String s = fc.getSelectedFile().getPath();
            if ( bEditor )
            	this.bLEditor.readLevel( s );
            else
            	this.bLGame.readLevel( s );
            //System.out.println("s = "+s);
        }
	}
	
	public void setLoadFirstLevel()
	{
		String s	= System.getProperty("user.dir") + File.separator+"levels"+File.separator+ "Orginal.bomb";
		this.bLGame.readLevel( s );
		this.bPG.setLoadLevel( this.bLGame, 0 );
	}
	
	public BombLevel getBombLevelGame()
	{
		return this.bLGame;
	}
	
	public BombLevel getBombLevelEditor()
	{
		return this.bLEditor;
	}
	
	public void setBombLevel( BombLevel bL )
	{
		this.bLEditor	= bL;
	}
	
	public static void main(String[] args)
	{
		new BombMain();
	}
}
```
- Fenster zentriert durch:

```
this.pack();
setLocationRelativeTo(null);
this.setVisible(true); // setzt das Fenster auf sichtbar*/
```
- getprefferedSize in den BombPanels gesetzt:

```
public Dimension getPreferredSize() 
{
        return new Dimension( 640, 480);
}
```
In der BombMain habe ich das anachronistisch anmutende Nulllayout durch ein modernes BorderLayout ersetzt.

Damit das Porgramm auch unter Linux läuft mußte ich diese Abfrage hinzufügen:

```
if ( !bFullScreenSupported  && this.myDevice.isDisplayChangeSupported())
{
            this.myDevice.setFullScreenWindow( this );
            this.myDevice.setDisplayMode( newDisplayMode );
}
```

Ausserdem habe ich alle Pfadangaben korrekt implementiert:

```
this.aSoundScream[i]    = new BombSounds( new File( System.getProperty("user.dir")+File.separator+"sounds"+File.separator+"Scream"+(i+1)+".wav") );
```
und hier auch nochmal:

```
String s	= System.getProperty("user.dir") + File.separator+"levels"+File.separator+ "Orginal.bomb";
```

Ich kann dir das komplette Projekt mit meinen Änderungen auch per Mail zukommen lassen, wenn du willst.

P.S. Weitere Tests folgen in Kürze ;-)

Viele Grüße,
foobar


----------



## Apo (20. Aug 2006)

Dank der Hilfe von foobar müsste das Spiel nun auch unter Linux laufen.

Das mit den Vektoren funktioniert aber nicht in diesem Beispiel, weil Sweety ein Rechteck ist und nicht nur ein Punkt.
Wenn die Bombe nun direkt unter Sweety "hochgeht", dann soll Sweety ja nur in y Richtung nach oben geschleudert werden ( ok fkt noch mit Vektoren ), aber wenn die Bombe dann in x Richtung verschoben wird muss ja die X-geschwindigkeit auch steigen ... aber nur bis zu einem gewissen Punkt, ab da muss sie wieder fallen.
Hach ist irgendwie schwerer als erwartet. Wollte bloss Sweety in die Luft jagen ... aber so einfach ist das gar nicht


----------



## André Uhres (21. Aug 2006)

Apo hat gesagt.:
			
		

> ..Wollte bloss Sweety in die Luft jagen ... aber so einfach ist das gar nicht


Vielleicht kann ein Sprengstoffexperte helfen  :lol:


----------



## foobar (21. Aug 2006)

Hier sind noch mal ein paar Anmwerkungen:
- Klasse BombThreadLogic: Hier würde ich anstatt eines Threads und sleep einen Timer mit scheduleAtFixedRate verwenden, um sicher zu stellen, daß der Thread auch wirklich nach n Millisekunden ausgeführt wird. Ansonsten kann es schon mal zu unerwünschten Delays kommen. Das gilt natürlich für alle Threads die millisekundengenau ausgeführt werden sollen.

- Wenn man Strings mit einer Konstanten vergleicht, sollte man immer über die Konstante die equals-Methode aufrufen, denn wenn der String null ist knallt es:

```
if ( ( hindrance.equals("links") ) || ( hindrance.equals("rechts") ) )
```
das schreibt man besser so:

```
if ("links".equals(hindrance) || "rechts".equals(hindrance) )
```
Die obsoleten Klammern kannst du dir auch sparen.

- Wenn du eine Exception fängst, gib zumindest den Stacktrace aus oder verwende einen Logger.

- Strings wie diese hier:

```
this.Buttons[0]			= new BombButton( this.bI.setPicsMain( "/images/game_hud_button_menu.png", false ), 580, 10, 50, 60, "Menu" );
```
sollten immer als Konstanten am Anfang der Klasse deklariert werden, um sie später leichter ändern zu können. Wenn du eine Konstante an mehrern Stellen im Code verwendest, packst du sie einfach in ein Interface BombConstants oder sowas. Dann kannst du von überall darauf zugreifen.

- Auch gilt wieder zuerst die Konstante, dann die Variable:

```
if ( bReady == false )
```
Hier wird schnell aus einer Überprüfung eine Wertzuweisung, wenn du das aber so schreibst:

```
if (false == bReady)
```
oder besser noch so:

```
if (!bReady)
```
bist du immer auf der sicheren Seite.

- Anstatt eines Vectors solltest du immer das Interface List verwenden:

```
Vector vString 	= new Vector();
```
schreibt man besser so:

```
List vString = new ArrayList();
```
wenn du Java 1.5 verwendest, solltest du auch gebrauch von Generics machen:

```
List<Integer> vString = new ArrayList<Integer>();
```
Damit ist deine Collection typsicher.

Hier gilt auch wieder das selbe:

```
@SuppressWarnings("unchecked")
	public Vector getWallVector( int k )
```
Verwende das Interface List und Generics, dadurch bist du unabhängig vom Vector.

- Das kann man auch einfacher haben:

```
if(s != null)
            return ((s.equals("bomb")));
        else
            return false;
```
wird zu:

```
return "bomb".equals(s);
```
Denn wenn s null ist, wird jetzt einfach false zurück gegeben.

Das else kannst du dir sparen:

```
if ( ( xSpeed > 3 ) || ( Math.abs( ySpeed ) > 4.5 ) )
			{
				this.bBrick			= false;
				this.time			= System.nanoTime();
				return s+"Hit";
			} else
			{
				return s;
			}
```
wird zu:

```
if ( ( xSpeed > 3 ) || ( Math.abs( ySpeed ) > 4.5 ) )
{
	this.bBrick			= false;
	this.time			= System.nanoTime();
	return s+"Hit";
} 
return s;
```

Du solltest deinen Code nie mit Tabs einrücken, das kann auf anderen Plattformen bzw. einer anderen IDE ganz furchtbar aussehen. In Eclipse kannst du Tabs durch Blanks ersetzten, das ist sehr hilfreich ;-)

Das Panel mit den Buttons im unteren Bereich des Spiels könnte etwas ordentlicher ausgerichtet sein. Die Abstände zwischen den einzelnen Widgets sollten einen einheitlichen Abstand haben und auf einer Höhe sein. Im Moment ist das alles noch einwenig wild. 

Ansonsten super Programm  :applaus: 

Viele Grüße,
foobar


----------



## Apo (21. Aug 2006)

hui danke danke

habe das jetzt mal mit dem Timer probiert ABER irgendwie sieht es jetzt aus, als ob es "laggt". Habe sowohl das Painten als auch die eigentliche "Logik" des Spiels jeweils einen Timer gegeben.
Das ist irgendwie unpraktisch, weil davor sah es ja wenigstens flüssig aus. Vielleicht habe ich ja was an der Timer Sache falsch gemacht.

Ich hab den Timer so gelöst:

Aufrufen tue ich es mit: 

```
this.bTLThink		= new BombTimerLogic( this, 10, true );
this.bTLThink.start();
this.bTLPaint		= new BombTimerLogic( this, 20, false );
this.bTLPaint.start();
```

und jetzt die beiden Klassen


```
package bomb;

import java.util.Timer;

public class BombTimerLogic
{
	private BombPanelGame		bPG;
	
	private BombTimerTask		bTT;
	
	private int 				delay;
	
	private Timer				timer;
	
	private boolean				bThink;
	
	public BombTimerLogic( BombPanelGame bPG, int delay, boolean bThink )
	{
		super();

		this.bPG		= bPG;
		this.delay		= delay;
		this.bThink		= bThink;
		
		this.timer		= new Timer();
		
		this.bTT		= new BombTimerTask( this.bPG, this.bThink, this.delay );
	}

	/**
	 * startet den Timer
	 */
	public void start()
	{
		this.timer.scheduleAtFixedRate( this.bTT, 0, this.delay );
	}
	
	/**
	 * beendet den Timer
	 */
	public void stop()
	{
		this.timer.cancel();
	}

}
```


```
package bomb;

import java.util.TimerTask;

public class BombTimerTask extends TimerTask
{
	
	private BombPanelGame	bPG;
	private boolean			bThink;
	private int				delay;
	
	public BombTimerTask( BombPanelGame bPG, boolean bThink, int delay )
	{
		super();

		this.bPG		= bPG;
		this.bThink		= bThink;
		this.delay		= delay;
	}

	@Override
	public void run()
	{
		if ( !this.bThink )
			this.bPG.repaint();
		else
			this.bPG.think( this.delay );
	}

}
```

Was habe ich falsch gemacht???


----------



## foobar (21. Aug 2006)

Dein Code sieht so weit korrekt aus. Ich würde aber nur den BombTimer als Timer starten, da es hier darauf ankommt, daß der Thread genau nach N Millisekunden gestartet wird. Beim HauptFrame ist das nicht so wichtig ob da mal ein repaint vergessen wird oder nicht.


----------



## Apo (21. Aug 2006)

so habe jetzt den "Paint"Thread wieder eingeführt und versuche die Bombenlogik über den Timer zu handeln ... aber so richtig glücklich bin ich immer noch nicht. 

Vielleicht kriege ich es ja noch hin, sonst wechsle ich wieder zu der alten Methode mit den Threads.
Der Rest der Beanstandungen sind bis auf den Logger alle verbessert worden (bzw versucht worden  )


----------



## foobar (21. Aug 2006)

> Vielleicht kriege ich es ja noch hin, sonst wechsle ich wieder zu der alten Methode mit den Threads.


Vielleicht war das mit dem Timer auch keine so gute Idee. In einem Spiel habe ich das noch nie ausprobeirt, aber mit ist in einem anderen Zusammenhang aufgefallen, daß bei normalen Threads mit sleep manchmal Iterationen ausgelassen werden.



> Der Rest der Beanstandungen sind bis auf den Logger alle verbessert worden (bzw versucht worden


Sehr löblich


----------



## internetto (21. Aug 2006)

Hallo,

nettes Programm, mir sind aber ein paar sache aufgefallen:

1. Ich würde den Rahmen um die bomben wegmachen (sowohl unten in der Leits eauls auch im Spielfeld)
2. Die bomben bei einem klick aufs Spielfeld befördern
3.Ich würde eine Hilfe hinzufügen, da ich nicht ganz so verstehe, was diese balken unten am spielfeldrand bewirken
4. Bei rausschleudern aus dem Spielfeld wäre es doch logisch, wenn de bombe weg ist, oder?

MfG
internetto


----------



## Guest (21. Aug 2006)

verstehe dich nicht so richtig ...

ok das mit dem Rahmen könnte man machen ... es war bloss dafür gedacht, wenn man eine Bombe per Linksklick im Spielfeld anwählt dann sieht man im Hud (also unten) welche Bombe es ist und wann sie "hochgeht".

Der Schieberegler unten im Hud ist zur Einstellung der Zeit, wann die Bombe explodieren soll. Es funktioniert wie ein Slider.

Beim rauschleudern aus dem Spielfeld ist die Bombe auch weg, bloss wird das Spiel wieder in die Ausgangsposition gebracht wenn Sweety aus dem Spielfeld fliegt (außer nach oben)
Aber wenn Sweety z.B. links aus dem Spielfeld fliegt, dann resetet das Spiel automatisch, weil Sweety dann nie und nimmer mehr ins Ziel gelangen kann.

Die Bomben kann man doch per Linksklick ins Spielfeld befördern ... verstehe nicht so richtig was du meinst.
Mit einem Rechtsklick auf die Bombe kannst du sie wieder ins Hud bringen.


----------



## simon_m (22. Aug 2006)

Hab das Spiel jetzt auch einmal getestet. Muss sagen, es ist ganz witzig! Vll schaffst du es ja noch, dass man die Bomben per Drag and Drop aus dem Hud ins SPiel bringen kann. Das ist aber nur eine Kleinigkeit! Ansonsten: keine Bugs und ein sehr gutes Look and Feel! Saubere Arbeit!


----------



## Schnitter (22. Aug 2006)

Ich kann noch ein Weniug mekern 

Z.b kann man die Bomben unter die Leiste unten schiebem =(

Eine replay-fubktion währe dabei noch genial


----------



## Apo (24. Aug 2006)

aloha

habe wieder mal ein bissl dran gearbeitet (z.B. kann man die Bomben jetzt nicht mehr komplett außerhalb platzieren) und mal eine BufferStrategy zum ersten mal ausprobiert mit dem GageTimer.
Dazu habe ich jetzt auch gleich 3 Fragen ...

1.) €dit: hab ich schon gelöst

2.) Ich nehme die BufferStrategy zum Neuzeichnen. Jetzt hatte ich vorher ein JFrame mit vielen JPanel's und habe diese mit repaint() gezeichnet. Soweit so gut. Das konnte ich ja ändern, weil ich jetzt ja von Canvas erbe. Aber im Editor hatte ich JTextField's ... wenn ich aber kein JPanel's habe bzw das nicht zu einem JFrame geaddet wird, dann kann ich es auch nicht benutzen bzw sie nicht sehen.
Also meine Frage ist ... wie kann ich weiterhin JPanel's benutzen? und falls das nicht geht, wie kann ich dann JTextField's einbauen?

Die BufferStrategy mache ich folgendermaßen:

```
public class BombMain extends Canvas implements MouseListener, MouseMotionListener
{
...
public BombMain()
	{
		super();
		
		this.frame		= new JFrame();
		
		this.frame.setTitle( "=== BombSweety ===" );
		
		...
		
		this.bombImage		= new BombImage( this );
		
		this.bombGame			= new BombGame( this, this.bombImage );
		this.bombMenu			= new BombMenu( this, this.bombImage );
		
		JPanel panel = (JPanel) this.frame.getContentPane();
		panel.setPreferredSize( new Dimension( 640,480 ) );
		panel.setLayout(null);
		
		this.setBounds( 0, 0, 640, 480 );
		
		panel.add( this );
		
		this.sCurrentDirectory		= "";
        
		BombImage AFI	= new BombImage( this );
		this.frame.setIconImage( AFI.setPicsMain( "/images/Icon.gif", false ) );
		
		this.setIgnoreRepaint( true );
		
		this.frame.addWindowListener(new WindowAdapter()
			{
				public void windowClosing(WindowEvent e)
				{
					System.exit(0);
				}
			}
		);
		
		this.addMouseListener( this );
		this.addMouseMotionListener( this );
		
		this.bombEditor			= new BombEditor( this, this.bombImage );
		this.bombEditor.setBombLevelHud( this.bombLevelEditor );
		
		this.bGame		= false;
		this.bEditor	= false;
		this.bOptions	= false;
		this.bMenu		= true;
		
		this.frame.pack();
		this.frame.setResizable(false);
		this.frame.setVisible(true);
		
		this.createBufferStrategy(2);
		this.strategy		= this.getBufferStrategy();
		
		this.gameLoop();
	}
```

und mein GameLoop sieht folgendermaßen aus:

```
public void gameLoop()
	{
		while ( this.bGameRunning )
		{
			//Get hold of a graphics context for the accelerated 
			// surface and blank it out
			this.g = (Graphics2D) strategy.getDrawGraphics();
			
			if ( ( this.bombGame != null ) && ( this.bGame ) )
			{
				this.bombGame.frameRenderer( g );
			} else if ( ( this.bombMenu != null ) && ( this.bMenu ) )
			{
				this.bombMenu.frameRenderer( g );
			} else if ( ( this.bombEditor != null ) && ( this.bEditor ) )
			{
				this.bombEditor.frameRenderer( g );
			}

			// finally, we've completed drawing so clear up the graphics
			// and flip the buffer over
			this.g.dispose();
			this.strategy.show();
		}
		System.exit( 0 );
	}
```

3.)  €dit: hab ich gelöst


Ich danke schonmal im Vorraus


----------



## foobar (24. Aug 2006)

Mach doch einfach ein pack() auf dem Frame, dann mußt du keine absoluten Werte setzen.


----------



## Apo (26. Aug 2006)

Guten Abend,

da ich es jetzt hinbekommen habe, die externe Jar mit einzubinden, steht eine neue Version online.
Was ist neu?
1.) Ich male nun konstant mithilfe der BufferStrategy (und versuche auf 100 fps durchgängig zu kommen)
2.) Sweety muss nun mindestens mit der Hälfte im Ziel sein, um den Sieg gelten zu lassen.
3.) Falls Sweety oben aus dem Bildschirm fliegt, sieht man nun ein kleines schwarzes Viereck am oberen Framerand, damit man weiß, wo sich Sweety befindet.
4.) Mithilfe der Tasten 1 bis 5 lassen sich die Bomben nun ins Spiel einsetzen bzw. wieder entfernen
5.) die Bomben können nur noch innerhalb des Frames platziert werden


Jetzt habe ich nur noch eine Frage, die bis jetzt unbeantwortet blieb. Ich hoffe, die Frage 2 Postings über mir, kann mir noch jemand beantworten bzw helfen.


----------



## RawBit (26. Aug 2006)

foobar hat gesagt.:
			
		

> Wow, sieht super aus  :applaus:
> 
> Aber warum gibt es das Spiel nur in Form einer Exe?



weil exe eben das beste is  :bae:


----------



## foobar (26. Aug 2006)

Hackl hat gesagt.:
			
		

> foobar hat gesagt.:
> 
> 
> 
> ...



Dadurch geht aber die Plattformunabhängigkeit verloren.


----------



## RawBit (26. Aug 2006)

tja schon aber exe is eben praktischer, es kann zB nicht wie ne zip entpackt werden und man kann ein eigenes icon machen...


----------



## moormaster (26. Aug 2006)

Hackl hat gesagt.:
			
		

> tja schon aber exe is eben praktischer, es kann zB nicht wie ne zip entpackt werden und man kann ein eigenes icon machen...



Wieso programmierst du das dann in Java, wenn dus als exe haben willst? Wieso sollte man deine Java-exe eigentlich nicht entpacken können? Bevor die exe die VM startet, müssen doch eh die Classfiles vorher extrahiert werden.
Icons kann man übrigens auch in den Verknüpfungen zu einer Datei (z.B. batch) festlegen.


----------



## Apo (30. Aug 2006)

Naja, ich finde eine "exe" auf jeden fall sicherer, wenn man seinen Code schützen möchte, weil z.B. Decafe kann jeder bedienen und somit ist eine class Datei nicht mehr sicher.

Aber warum ich nochmal schreibe ... kann mir wirklich keiner helfen, wie ich ein JFrame mit allen Vorteilen von den JPanels usw. nutzen kann wenn ich eine BufferStrategy benutze?
Habe einiges ausprobiert, aber ich darf scheinbar die BufferStrategy nicht von dem JFrame nehmen in das ich auch male, weil sonst kommt er bei mir gar nicht mehr klar.
Hat keiner eine Lösung? Ich habe es halt probiert, weil ich von JFrame erbe, die BufferStrategy zu bekommen ... klappt auch wunderbar ... aber wenn ich Sie dann anwende, wie ein paar Postings über mir beschrieben, vergisst das JFrame, dass es JPanels hat und diese genau positioniert sind. Und stellt alles an der Stelle 0,0 vom Frame dar.
Was mache ich falsch?
Ich möchte doch nur JPanels nutzen ...


----------



## Apo (2. Sep 2006)

so da mir scheinbar leider keiner helfen kann, habe ich eine andere Frage:

Um die Sache zu umgehen, möchte ich jetzt einfach ein TextField einfügen. Aber meine Klasse erbt ja nicht von JPanel oder JFrame oder Component -> kann ich kein TextField hinzufügen, weil man es ja nicht sieht bzw adden kann. Kann ich irgendwie ein TextField oder JTextField hinzufügen, obwohl ich ja nicht von den Sachen erbe ... bzw wie schaffe ich es, das es klappt?


----------



## foobar (3. Sep 2006)

Welcher Klasse willst du denn ein TextField hinzufügen?


----------



## Apo (15. Sep 2006)

[OFFTOPIC]
Sorry das ich jetzt erst anworte ... so ein Kreuzbandriss ist schon nichts feines
[/OFFTOPIC]

Also ich möchte gerne im EditorHud ein TextField hinzufügen. Weiß bloss nicht wie ich das schaffen kann.


----------

