Surface View - RenderThread Problem

  • 30 Antworten
  • Letztes Antwortdatum
um die laufzeit zu verbessern würde ich anstatt nanotime lieber System.currenttimeMillis(); benutzen diese anweisung läuft 20-30 mal schneller(ca.5-6 CPU Clocks während nano um die 100+ braucht) und diese ganzen aufrufe an paint.setStyle etc solltest du auch ncih immer wieder neu machen die kosten auch performance:setStyle/setAllign/setTypeface/setTextSize brauchst du doch nur ein einziges mal machen oder? wenn du das immer und immer wieder amchst ist das nciht gut für die laufzeit.
Und iwe schon gesagt du brauchst nun wirklihc nciht nochmal alles schwarz malen(canvas.drawRGB(0,0,0);) du machst schon ein doublebuffer weil du erstmal den canvas manipulierst und wenn er fertig ist sofort auf den bildschirm flaschst;)

Der ursprüngliche Beitrag von 21:26 Uhr wurde um 21:28 Uhr ergänzt:

könnte schon sein dass du dann auf 50-60 fps kommst
 
Aber ohne den double buffer ueberlagert sich der fps text und wird unlesbar,
Ebenso die rechtecke. Anstatt dass es kleiner wird bekomme ich unendlich viele,
Uebereinander liegende, kleinerwerdende rechtecke. Ich male also auf das letzte bild.
wenn ich paint.setTextSize nicht nochmal einbaue nachdem ich canvas.drawRect aufrufe
Ist die textgroesse winzig. Eine loesung hierfuer waere vll eine paint2 du definieren?

Der tipp mit millis ist gut ;) aber ich versteh leider immernoch nicht wieso der seperate render thread 100x langsamer ist als per invalidate den mainthread neu aufzurufen :(
 
eigentlich sollte sich die surfaceview schneller als die normale view zeichnen lassen vllt liegt es an der implementierung mmmmh

Der ursprüngliche Beitrag von 23:28 Uhr wurde um 23:33 Uhr ergänzt:

wenn du lust hast versuch die variante die ich in meinem allerersten post hier beschrieben habe mit der surfaceview die einen inneren workerthread hat der diese aktualisiert
ist deiner variante ähnlich nur besser :)P) weil er den callback noch drin hat
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: Railwanderer
Hier ein kleines Beispiel aus meinem fast fertigen Game(Grafik sind schlecht)

PHP:
package de.jaielsoft.surfaceviews;


import de.jaielsoft.activities.R;
import de.jaielsoft.threads.MainThread;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MainView extends SurfaceView implements SurfaceHolder.Callback
{	
	
	
	//__________________________________________//
	MainThread mThread;
	SurfaceHolder sHolder;
	Intent intent;
	Canvas canvas;
	
	public boolean startedForFirstTime=true,exit,play,surfaceReady,soundOn,playButtonDown,exitButtonDown,soundButtonDown;
	Paint paint=new Paint();

	Bitmap ddot=BitmapFactory.decodeResource(getResources(),R.drawable.ddot);
	Bitmap odot=BitmapFactory.decodeResource(getResources(),R.drawable.odot);
	Bitmap tdot=BitmapFactory.decodeResource(getResources(),R.drawable.tdot);
	Bitmap exitarrow=BitmapFactory.decodeResource(getResources(),R.drawable.exitarrow);
	Bitmap exitdoor=BitmapFactory.decodeResource(getResources(),R.drawable.exitdoor);
	Bitmap playbutton=BitmapFactory.decodeResource(getResources(),R.drawable.playbutton);
	Bitmap soundonbutton=BitmapFactory.decodeResource(getResources(),R.drawable.soundonbutton);
	Bitmap soundoffbutton=BitmapFactory.decodeResource(getResources(),R.drawable.soundoffbutton);
	Bitmap dotbackground=BitmapFactory.decodeResource(getResources(),R.drawable.dotbackground);
	

	//__________________________________________//
	
	
	/*
	 * Constructor
	 */
	public MainView(Context context) {
		super(context);
		sHolder = getHolder();
		sHolder.addCallback(this);
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) 
	{}

	@Override
	public void surfaceCreated(SurfaceHolder sHolder) {
		surfaceReady=true;
		if(startedForFirstTime)
		{
			mThread=new MainThread(this);
			scaleBitmaps();
			startMainThread();
			startedForFirstTime=false;
		}
		mThread.setPause(false);
		
		
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		surfaceReady=false;
		mThread.setPause(true);
	}
	
	
	@Override
	public boolean onTouchEvent(MotionEvent e) 
	{
		super.onTouchEvent(e);
		float X=e.getX();
		float Y=e.getY();
		  switch(e.getAction())
		  {
		  	case MotionEvent.ACTION_DOWN:
		  		if(	X>mThread.playButton.posX-playbutton.getWidth()/2&&
			  		Y>mThread.playButton.posY-playbutton.getHeight()/2&&
			  		X<mThread.playButton.posX+playbutton.getWidth()/2&&
			  		Y<mThread.playButton.posY+playbutton.getHeight()/2)
			  	{
		  			playButtonDown=true;
			  	}
		  		else playButtonDown=false;

		  		if(	X>mThread.soundButton.posX-soundonbutton.getWidth()/2&&
		  			Y>mThread.soundButton.posY-soundonbutton.getHeight()/2&&
		  			X<mThread.soundButton.posX+soundonbutton.getWidth()/2&&
		  			Y<mThread.soundButton.posY+soundonbutton.getHeight()/2)
		  		{
		  			soundButtonDown=true;
		  		}
		  		else soundButtonDown=false;
		  			

		  		if(	X>mThread.exitDoor.posX-exitdoor.getWidth()/2&&
		  			Y>mThread.exitDoor.posY-exitdoor.getHeight()/2&&
		  			X<mThread.exitDoor.posX+exitdoor.getWidth()/2&&
		  			Y<mThread.exitDoor.posY+exitdoor.getHeight()/2)
		  		{
		  			exitButtonDown=true;
		  		}
		  		else exitButtonDown=false;
		  		break;
		  		
		  	case MotionEvent.ACTION_MOVE:
		  		break;
		  	
		  	case MotionEvent.ACTION_UP:
		  		if(	X>mThread.playButton.posX-playbutton.getWidth()/2&&
			  		Y>mThread.playButton.posY-playbutton.getHeight()/2&&
			  		X<mThread.playButton.posX+playbutton.getWidth()/2&&
			  		Y<mThread.playButton.posY+playbutton.getHeight()/2&&
			  		playButtonDown)
	  			{
		  			
	  				play=true;
	  				playButtonDown=false;
	  				
	  			}

		  		if(	X>mThread.soundButton.posX-soundonbutton.getWidth()/2&&
		  			Y>mThread.soundButton.posY-soundonbutton.getHeight()/2&&
		  			X<mThread.soundButton.posX+soundonbutton.getWidth()/2&&
		  			Y<mThread.soundButton.posY+soundonbutton.getHeight()/2&&
		  			soundButtonDown)
		  		{
		  			if(soundOn)soundOn=false;
		  			else soundOn=true;
		  			soundButtonDown=false;
		  			
		  		}

		  		if(	X>mThread.exitDoor.posX-exitdoor.getWidth()/2&&
		  			Y>mThread.exitDoor.posY-exitdoor.getHeight()/2&&
		  			X<mThread.exitDoor.posX+exitdoor.getWidth()/2&&
		  			Y<mThread.exitDoor.posY+exitdoor.getHeight()/2&&
		  			exitButtonDown)
	  			{
		  			exitButtonDown=false;
	  			}
		  			
		  		performClick();
		  		break;
		  }
		   
		  return true;
	}
	@Override
	 public boolean performClick() {
	  // Calls the super implementation, which generates an AccessibilityEvent
	        // and calls the onClick() listener on the view, if any
	        super.performClick();

	        // Handle the action for the custom click here

	        return true;
	 }
	/*
	 * Method for the drawing operations.
	 */
	public void doDraw()
	{
		try
		{
			canvas = sHolder.lockCanvas();
			synchronized(sHolder)
			{
				//drawing operations here
				canvas.drawBitmap(dotbackground,0,0,null);
				if(soundOn)canvas.drawBitmap(soundonbutton,mThread.soundButton.posX-soundonbutton.getWidth()/2,mThread.soundButton.posY-soundonbutton.getHeight()/2,null);
				else canvas.drawBitmap(soundoffbutton,mThread.soundButton.posX-soundonbutton.getWidth()/2,mThread.soundButton.posY-soundonbutton.getHeight()/2,null);
				canvas.drawBitmap(exitdoor,mThread.exitDoor.posX-exitdoor.getWidth()/2,mThread.exitDoor.posY-exitdoor.getHeight()/2,null);
				canvas.drawBitmap(exitarrow,mThread.exitArrow.posX-exitarrow.getWidth()/2,mThread.exitArrow.posY-exitarrow.getHeight()/2,null);
				canvas.drawBitmap(ddot,mThread.dDot.posX-ddot.getWidth()/2,mThread.dDot.posY-ddot.getHeight()/2,null);
				canvas.drawBitmap(tdot,mThread.tDot.posX-tdot.getWidth()/2,mThread.tDot.posY-tdot.getHeight()/2,null);
				canvas.drawBitmap(odot,mThread.oDot.posX-odot.getWidth()/2,mThread.oDot.posY-odot.getHeight()/2,null);
				canvas.drawBitmap(playbutton,mThread.playButton.posX-playbutton.getWidth()/2,mThread.playButton.posY-playbutton.getHeight()/2,null);
				
				
			}
		}
		catch(Throwable t)
		{
			canvas=null;
		}
		finally
		{
			if(canvas!= null)
			{
				sHolder.unlockCanvasAndPost(canvas);
			}
		}
	}
	
	
	
	
	
	
	public int startMainThread()
	{
		if(surfaceReady)
		{
			mThread.setRunning(true);
			try
			{
				mThread.start();
				return 0;
			}
			catch(Throwable t)
			{
				return -1;
			}
		}
		else return -1;
		
	}
	
	public void scaleBitmaps()
	{
		float 	ddotscale=0.34f*(float)(getWidth()),
				odotscale=0.30f*(float)(getWidth()),
				tdotscale=0.34f*(float)(getWidth()),
				exitarrowscale=0.08f*(float)(getWidth()),
				exitdoorscale=0.1f*(float)getWidth(),
				playbuttonscale=0.5f*(float)(getWidth()),
				soundonscale=0.13f*(float)(getWidth()),
				soundoffscale=0.13f*(float)(getWidth());
		
		
		ddot=Bitmap.createScaledBitmap(ddot,(int)ddotscale,(int)((float)ddot.getHeight()/(float)ddot.getWidth()*ddotscale),true);
		odot=Bitmap.createScaledBitmap(odot,(int)odotscale,(int)((float)odot.getHeight()/(float)odot.getWidth()*odotscale),true);
		tdot=Bitmap.createScaledBitmap(tdot,(int)tdotscale,(int)((float)tdot.getHeight()/(float)tdot.getWidth()*tdotscale),true);
		exitarrow=Bitmap.createScaledBitmap(exitarrow,(int)exitarrowscale,(int)((float)exitarrow.getHeight()/(float)exitarrow.getWidth()*exitarrowscale),true);
		exitdoor=Bitmap.createScaledBitmap(exitdoor,(int)exitdoorscale,(int)((float)exitdoor.getHeight()/(float)exitdoor.getWidth()*exitdoorscale),true);
		playbutton=Bitmap.createScaledBitmap(playbutton,(int)playbuttonscale,(int)((float)playbutton.getHeight()/(float)playbutton.getWidth()*playbuttonscale),true);
		soundonbutton=Bitmap.createScaledBitmap(soundonbutton,(int)soundonscale,(int)((float)soundonbutton.getHeight()/(float)soundonbutton.getWidth()*soundonscale),true);
		soundoffbutton=Bitmap.createScaledBitmap(soundoffbutton,(int)soundoffscale,(int)((float)soundoffbutton.getHeight()/(float)soundoffbutton.getWidth()*soundoffscale),true);
		dotbackground=Bitmap.createScaledBitmap(dotbackground,getWidth(),getHeight(),true);
	}
	
	
	public void killMainThread()
	{
		mThread.setRunning(false);
		mThread.setPause(true);

		boolean retry = true;
		while(retry)
		{
			try
			{
				mThread.join();
				retry = false;
			}
			catch(Exception e)
			{}
		}
		
		exit=true;
	}
	
	

}

sieht dann so aus(ich weiß ich weiß kacke :D)
 

Anhänge

  • Screenshot_2015-02-24-23-50-05.png
    Screenshot_2015-02-24-23-50-05.png
    100,3 KB · Aufrufe: 147
  • Danke
Reaktionen: Railwanderer
du siehst auch dass ich alle berechnungen in dem seperaten mainthread ausführe und nur zeichen operationen in der doDraw() methode ausführe

Der ursprüngliche Beitrag von 23:54 Uhr wurde um 23:56 Uhr ergänzt:

und keine angst vor dem Callback das einzige was der implementiert sind die ersten drei override methoden diese definieren seinen lebenszyklus
surfaceCreated wird immer aufgerufen wenn der bildschrim sich grad neu aufgebaut hat(der perfekte ort um einen thread zu starten bzw. aus dem pausieren zu holen) und surfacedestroyed wenn dieser nicht mehr sichtbar ist(perfekt um den thread zu pausieren
 
  • Danke
Reaktionen: Railwanderer
Jawolllll :) canvas = null; wird es loesen :D und dass ohne 3 zeilen code ;)

ueber den callback habe ich schon in der android referenz nachgelesen, wollte
es aber erstmal bei seite lassen bis ich meine fehler verstanden habe , aber jetzt kanns
damot losgehen :D super man du bist echt klasse :) werde dein game aufiedenfall morgen
Testen, vielen dank schonmal dass du es zur Verfuegung stellst !
Leider muss ich nur morgen um 5:45 aufstehen und bis halb neun arbeiten :/ bin gegen
21uhr dann zuhause und werds dann auschecken! Bis morgen abend/ nacht :D

und nochmal danke fuer die muehen ;) ich glaube alleine wuerde ich immernoch am
Ersten fehler sitzen. Du bekommst natuerlich auch mein game zum testen...sobald
ich fertig bin, versprochen! ;) wird sich aber noch ein wenig ziehen bis es soweit ist :p
 
nene das ist nciht das game sondern nur der code für die surfaceview des menüs lol :D
ich arbeite ncoh daran werde es demnächst im playstore veröffentlichen...muss einige sachen ncoh einbauen vor allem sound(hab noch nie sellber sounds erstellt ist echt nciht meine welt) und werbung einbauen


kein problem ich helfe gerne:)

Der ursprüngliche Beitrag von 00:26 Uhr wurde um 00:29 Uhr ergänzt:

ich hab auch nebenbei ein kleines tutorial geschrieben wie man halt kleine games programmiert und wollte es im unterforum forum "CodeSchnisel" posten weil das hier moch fehlt irgendwie da werde ich dann auch alls genau erklären wie was wieso

Der ursprüngliche Beitrag von 00:29 Uhr wurde um 00:32 Uhr ergänzt:

hab grad was entdeckt:ich setz den canvas gar nciht auf null komischerweise...vllt hilft dir das doch nciht beid einem problem aber versuchs mal *verwirrt*
 
Hehe ja habs auch grad beim ueberfliegen des codes gemerkt ;)

du greifst canvas = null; aber in der throwable exception auf oder?
Heisst das bei jedem zweiten Frame gibts ein fehler der dann canvas null setzt?
oder vll uebermalt er nur den soundknopf und der alte liegt noch drunter?
interessant auch die scale Bitmap anweisungen, muss ich mir genau anschauen,
das pixel unabhaengige zeichnen macht mir auch noch probleme ;)
vorallem da sich ja auch height und width nach orientierung vertauschen :S

ich merk schon da kann ich noch einiges aus deinem beispiel lernen ;)
so ich bin nu aber weg ;) bis morgen! Und noch erfolgreiches coden ;)


Haha gleichzeitg das selbe gedacht ;) beweg mal was beim zeichnen dann siehst es direkt ;)
 
das zeichnen klappt wunderbar weil ich immer ein background male:
ok dann lass es bei canvas.drawColor(Color.BLACK); bevor du alles weitere malst...war schon richtig
 
jepp ich werde auch in Zukunft den canvas nicht zweimal locken und posten sondern einfach
als erstes schwarz malen und dann alle Änderungen zeichnen lassen,
das spart sicher auch Leistung, in meinem fall oben mit doppelten lock And Post sind ja
quasi 2 fps in einem ;)
 
Nur so nebenbei: bei Menüs kannst du das auch so implementieren dass der canvas nur bei Veränderungen neu zeichnen soll
das macht die ganze Applikation nochmal etwas performanter
 
Zurück
Oben Unten