Esempio 1 - Sfere in movimento

di il
3 risposte

Esempio 1 - Sfere in movimento

Ciao,

nei forum relativi ad iOS e Windows Phone sono cominciati dei thread (ad opera di Barba59 e Orso Bruno) sullo sviluppo di una semplice applicazione di una palla che rimbalza contro i bordi.

Mi piacerebbe fare la stessa cosa per Android.

Sono un principiante sotto Android: sono riuscito a installare tutto il necessario per lo sviluppo (Java, Eclipse, plugin per lo sviluppo android sotto eclipse etc.) ed anche a scrivere, compilare ed eseguire un Hello world. Ora mi piacerebbe passare alle palle

Visto che abbiamo già la stessa applicazione per windows mobile ed iPad trovo che questo sviluppo sarebbe interessante anche per fare dei confronti fra i vari sistemi.
Chi se la sente di aiutarmi? Io frattanto vedo di capire come si fa a disegnare una pallina.

Ciao, g.

3 Risposte

  • Re: Esempio 1 - Sfere in movimento

    Ciao GianmariaLari
    Vedo che c'é diverso fermento nell' area mobile! Bravi, bravi, bisogna tenersi aggiornati mica rimanere nel proprio brodo! :!

    Dato che siete tutti agli inizi mi aggrego pure io. Questa idea delle palle che girano é buona. Si puo fare  come applicazione normale  oppure come applicazione gioco, quindi ha 6 varianti. 

    Una domanda, in iOS per i giochi si usa OpenGL in Windows Phone XNA e in Android cosa si usa?
  • Re: Esempio 1 - Sfere in movimento

    Anche su android si usano le OpenGL!
  • Re: Esempio 1 - Sfere in movimento

    Ciao a tutti. Ecco la mia implementazione del tutorial. Ovviamente non è perfetta, quindi se qualcuno ha dei miglioramenti dica pure
    Una nota: in questo tutorial si usano dei metodi che sono stati introdotti solo dalla versione Honeycomb (API level 11), per cui è necessario creare un progetto nel cui manifest sia impostato un minSdk con valore almeno pari a 11.
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.sfere"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="11"
            android:targetSdkVersion="15" />
    
        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/title_activity_main" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    PREMESSA: Dal momento che in android non esiste un metodo simile a "scheduledTimerWithTimeInterval" (di Objective-C), e dato che solo il main-thread può intervenire sull'interfaccia grafica (per questo è spesso detto UI-Thread), questo tutorial risulterà più complesso rispetto a quello per l'objective-C. L'idea di base, comunque, è la stessa, ovvero richiamare un metodo ogni tot di tempo.

    Come si può vedere dal manifest postato precedentemente, tutti i miei file stanno all'interno del package com.example.sfere.

    Creiamo quindi un file xml di layout che, per semplicità, contiene solo il layout e l'immagine da muovere. Chiamiamolo main.
    Il contenuto di questo file sarà:
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        an[code]
    droid:layout_height="match_parent"
    android:id="@+id/main_layout" >

    <ImageView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/image"
    android:src="@drawable/ic_launcher"/>

    </FrameLayout>[/code]

    A questo punto possiamo occuparci dell'activity principale. Come già detto, quello che vogliamo fare è spostare l'immagine ogni tot secondi (in questo caso ogni decimo di secondo).
    Possiamo quindi creare un oggetto Timer e il relativo TimerTask, in cui il primo ci permette di pianificare delle operazioni, mentre il secondo specifica l'operazione da eseguire. La specializzazione della classe TimerTask (così come tutte le classi personalizzate che vedremo successivamente) è stata creata come classe privata all'interno della MainActivity per semplicità.
    package com.example.sfere;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.widget.FrameLayout;
    import android.widget.ImageView;
    
    public class MainActivity extends Activity {
    
    	private ImageView img;
    	private Timer timer;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    
    		img = (ImageView) findViewById(R.id.image);
    		timer = new Timer();
    
    	}
    
    	@Override
    	protected void onResume() {
    		super.onResume();
    
    		// Inizio a muovere l'immagine
    		timer.scheduleAtFixedRate(new MyTask(), 0L, 100L);
    	}
    
    	@Override
    	protected void onPause() {
    		super.onPause();
    		// Fermo il timer
    		timer.cancel();
    	}
    
    	private class MyTask extends TimerTask {
    
    		@Override
    		public void run() {
    			//Qua vanno le operazioni da eseguire
    		}
    
    	}
    }
    
    E' importante notare che le operazioni eseguite all'interno del TimerTask si trovano in un thread differente dall'UI-Thread, quindi non è possibile muovere l'immagine direttamente all'interno di esso. Quello che bisogna fare è "informare" l'UI-Thread di spostare questa immagine. Un possibile modo di effettuare questa comunicazione è tramite gli handler e i message, un meccanismo di comunicazione fondamentale in Android.
    Praticamente ad ogni thread è associata una mail box, dalla quale preleva ciclicamente gli eventuali messaggi presenti, i quali vengono gestiti dagli handler. Andando a creare una specializzazione della classe Handler, quindi, è possibile attribuire ad una determinata tipologia di messaggi un comportamento desiderato (attraverso il metodo handleMessage). Per tornare al nostro esempio, vogliamo associare a determinati messaggi la corrispondente azione di spostare l'immagine.

    Per fare ciò, quindi, creiamo una sottoclasse di Handler. Come già detto, anche la classe MyHandler è interna a MainActivity.
    
    	private class MyHandler extends Handler {
    
    		private float movement = 5F; // 5 pixel
    
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case MSG_MOVE: //MSG_MOVE è una costante definita in MainActivity
    				moveImage();
    				break;
    
    			default:
    				super.handleMessage(msg);
    				break;
    			}
    		}		
    
    		private void moveImage() {
    			float curX = img.getX(); // Valido per API Level > 11
    
    			// Controllo se l'immagine esce dallo schermo
    			FrameLayout layout = (FrameLayout) findViewById(R.id.main_layout);
    			int width = layout.getWidth();
    			if ((curX + img.getWidth()) > width || curX < 0) {
    				movement = -movement;
    			}
    
    			img.setX(curX + movement);
    		}
    
    	}
    
    
    Andiamo quindi a modificare la classe TimerTask per darle il comportamento desiderato (ovvero inviare un messaggio all'handler):
    
    private class MyTask extends TimerTask {
    		
    	private Handler handler = new MyHandler();
    
    	@Override
    	public void run() {
    		Message msg = handler.obtainMessage(MSG_MOVE);
    		handler.sendMessage(msg);
    	}
    
    }
    
    Dove MSG_MOVE è una costante definita nella classe MainActivity:
    
    public class MainActivity extends Activity {
    
    	private ImageView img;
    	private Timer timer;
    
    	public static final int MSG_MOVE = 1;
    
            ....
    }
    A questo punto non ci resta che avviare l'applicazione e vedere il risultato:
    device_screen.png
    device_screen.png

    Per completezza, il codice completo è questo:
    package com.example.sfere;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.widget.FrameLayout;
    import android.widget.ImageView;
    
    public class MainActivity extends Activity {
    
    	private ImageView img;
    	private Timer timer;
    
    	public static final int MSG_MOVE = 1;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    
    		img = (ImageView) findViewById(R.id.image);
    		timer = new Timer();
    
    	}
    
    	@Override
    	protected void onResume() {
    		super.onResume();
    
    		// Inizio a muovere l'immagine
    		timer.scheduleAtFixedRate(new MyTask(), 0L, 100L);
    	}
    
    	@Override
    	protected void onPause() {
    		super.onPause();
    		// Fermo il timer
    		timer.cancel();
    	}
    
    	private class MyTask extends TimerTask {
    		
    		private Handler handler = new MyHandler();
    
    		@Override
    		public void run() {
    			Message msg = handler.obtainMessage(MSG_MOVE);
    			handler.sendMessage(msg);
    		}
    
    	}
    
    	private class MyHandler extends Handler {
    
    		private float movement = 5F; // 10 pixel
    
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case MSG_MOVE:
    				moveImage();
    				break;
    
    			default:
    				super.dispatchMessage(msg);
    				break;
    			}
    		}		
    
    		private void moveImage() {
    			float curX = img.getX(); // Valido per API Level > 11
    
    			// Controllo se l'immagine esce dallo schermo
    			FrameLayout layout = (FrameLayout) findViewById(R.id.main_layout);
    			int width = layout.getWidth();
    			if ((curX + img.getWidth()) > width || curX < 0) {
    				movement = -movement;
    			}
    
    			img.setX(curX + movement);
    		}
    
    	}
    
    }
    
Devi accedere o registrarti per scrivere nel forum
3 risposte