Hướng dẫn lập trình game Android đơn giản sử dụng Android Studio (Phần 3)

Đăng bởi: Admin | Lượt xem: 3153 | Chuyên mục: Game

Mục tiêu của tài liệu hướng dẫn bạn làm quen với một vài kỹ thuật đơn giản trong lập trình Game 2D Android. Bao gồm: sử dụng SuffaceView, vẽ trên Canvas, chuyển động của các , nhân vật game, tương tác với cử chỉ của người chơi.


Xem phẩn 1 tại đây

Xem phần 2 tại đây

6- Tương tác với người chơi (Version: 3)

Tiếp theo bạn có xử lý sự kiện khi người dùng chạm vào màn hình, nhân vật trò chơi sẽ chạy theo hướng bạn đã chạm. Bạn cần xử lý sự kiện này trên lớp GameSurface.

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        int x=  (int)event.getX();
        int y = (int)event.getY();
 
        int movingVectorX =x-  this.chibi1.getX() ;
        int movingVectorY =y-  this.chibi1.getY() ;
 
        this.chibi1.setMovingVector(movingVectorX,movingVectorY);
        return true;
    }
    return false;
}

Xem code đầy đủ:

GameSurface.java

package org.o7planning.android2dgame;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
 
    private GameThread gameThread;
 
    private ChibiCharacter chibi1;
 
    public GameSurface(Context context)  {
        super(context);
 
        // Make Game Surface focusable so it can handle events.
        this.setFocusable(true);
 
        // Set callback.
        this.getHolder().addCallback(this);
    }
 
    public void update()  {
        this.chibi1.update();
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            int x=  (int)event.getX();
            int y = (int)event.getY();
 
            int movingVectorX =x-  this.chibi1.getX() ;
            int movingVectorY =y-  this.chibi1.getY() ;
 
            this.chibi1.setMovingVector(movingVectorX,movingVectorY);
            return true;
        }
        return false;
    }
 
    @Override
    public void draw(Canvas canvas)  {
        super.draw(canvas);
 
        this.chibi1.draw(canvas);
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
        this.chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
 
        this.gameThread = new GameThread(this,holder);
        this.gameThread.setRunning(true);
        this.gameThread.start();
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry= true;
        while(retry) {
            try {
                this.gameThread.setRunning(false);
 
                // Parent thread must wait until the end of GameThread.
                this.gameThread.join();
            }catch(InterruptedException e)  {
                e.printStackTrace();
            }
            retry= true;
        }
    }
 
}

Chạy lại trò chơi:

7- Trò chơi với nhiều nhân vật (Version: 4)

Bạn có thể tạo thêm các nhân vật khác vào trò chơi, ở đây tôi thêm một nhân vật thứ 2. Sửa lại code của lớp GameSurface:

GameSurface.java

package org.o7planning.android2dgame;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
import java.util.ArrayList;
import java.util.List;
 
public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
 
    private GameThread gameThread;
 
    private final List<ChibiCharacter> chibiList = new ArrayList<ChibiCharacter>();
 
    public GameSurface(Context context)  {
        super(context);
 
        // Make Game Surface focusable so it can handle events.
        this.setFocusable(true);
 
        // Set callback.
        this.getHolder().addCallback(this);
    }
 
    public void update()  {
        for(ChibiCharacter chibi: chibiList) {
            chibi.update();
        }
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            int x=  (int)event.getX();
            int y = (int)event.getY();
 
            for(ChibiCharacter chibi: chibiList) {
                int movingVectorX =x-  chibi.getX() ;
                int movingVectorY =y-  chibi.getY() ;
                chibi.setMovingVector(movingVectorX, movingVectorY);
            }
            return true;
        }
        return false;
    }
 
    @Override
    public void draw(Canvas canvas)  {
        super.draw(canvas);
 
        for(ChibiCharacter chibi: chibiList)  {
            chibi.draw(canvas);
        }
 
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
        ChibiCharacter chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
 
        Bitmap chibiBitmap2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi2);
        ChibiCharacter chibi2 = new ChibiCharacter(this,chibiBitmap2,300,150);
 
        this.chibiList.add(chibi1);
        this.chibiList.add(chibi2);
 
        this.gameThread = new GameThread(this,holder);
        this.gameThread.setRunning(true);
        this.gameThread.start();
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry= true;
        while(retry) {
            try {
                this.gameThread.setRunning(false);
 
                // Parent thread must wait until the end of GameThread.
                this.gameThread.join();
            }catch(InterruptedException e)  {
                e.printStackTrace();
            }
            retry= true;
        }
    }
 
}

Chạy lại trò chơi.

8- Hiệu ứng trong trò chơi (Version: 5)

Đôi khi bạn cần phải xử lý một vài hiệu ứng cho trò chơi, chẳng hạn bạn đang điều khiển một cái máy bay, khi nó rơi xuống đất máy bay phát nổ, vậy nổ là một hiệu ứng. Trong phần này tôi sẽ mô phỏng khi bạn chạm (click) vào nhân vật Chibi, nó sẽ phát nổ.

Lớp Explosion mô phỏng một vụ nổ, khi bạn click vào nhân vật Chibi, nó bị loại ra khỏi trò chơi và một đối tượng Explosion được thêm vào trò chơi tại vị trí của nhân vật Chibi vừa bị loại bỏ.

Explosion.java

package org.o7planning.android2dgame;  
 
import android.graphics.Bitmap;
import android.graphics.Canvas;
 
public class Explosion extends GameObject {
 
    private int rowIndex = 0 ;
    private int colIndex = -1 ;
 
    private boolean finish= false;
    private GameSurface gameSurface;
 
    public Explosion(GameSurface GameSurface, Bitmap image, int x, int y) {
        super(image, 5, 5, x, y);
 
        this.gameSurface= GameSurface;
    }
 
    public void update()  {
        this.colIndex++;
 
        if(this.colIndex >= this.colCount)  {
            this.colIndex =0;
            this.rowIndex++;
 
            if(this.rowIndex>= this.rowCount)  {
                this.finish= true;
            }
        }
    }
 
    public void draw(Canvas canvas)  {
        if(!finish)  {
            Bitmap bitmap= this.createSubImageAt(rowIndex,colIndex);
            canvas.drawBitmap(bitmap, this.x, this.y,null);
        }
    }
 
    public boolean isFinish() {
        return finish;
    }
 
}

Bạn cần sửa code của lớp GameSurface:

GameSurface.java

package org.o7planning.android2dgame;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
 
    private GameThread gameThread;
 
    private final List<ChibiCharacter> chibiList = new ArrayList<ChibiCharacter>();
    private final List<Explosion> explosionList = new ArrayList<Explosion>();
 
    public GameSurface(Context context)  {
        super(context);
 
        // Make Game Surface focusable so it can handle events.
        this.setFocusable(true);
 
        // Sét callback.
        this.getHolder().addCallback(this);
    }
 
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
 
            int x=  (int)event.getX();
            int y = (int)event.getY();
 
            Iterator<ChibiCharacter> iterator= this.chibiList.iterator();
 
            while(iterator.hasNext()) {
                ChibiCharacter chibi = iterator.next();
                if( chibi.getX() < x && x < chibi.getX() + chibi.getWidth()
                        && chibi.getY() < y && y < chibi.getY()+ chibi.getHeight())  {
                    // Remove the current element from the iterator and the list.
                    iterator.remove();
 
                    // Create Explosion object.
                    Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),R.drawable.explosion);
                    Explosion explosion = new Explosion(this, bitmap,chibi.getX(),chibi.getY());
 
                    this.explosionList.add(explosion);
                }
            }
 
 
            for(ChibiCharacter chibi: chibiList) {
                int movingVectorX =x-  chibi.getX() ;
                int movingVectorY =y-  chibi.getY() ;
                chibi.setMovingVector(movingVectorX, movingVectorY);
            }
            return true;
        }
        return false;
    }
 
    public void update()  {
        for(ChibiCharacter chibi: chibiList) {
            chibi.update();
        }
        for(Explosion explosion: this.explosionList)  {
            explosion.update();
        }
 
        Iterator<Explosion> iterator= this.explosionList.iterator();
        while(iterator.hasNext())  {
            Explosion explosion = iterator.next();
 
            if(explosion.isFinish()) {
                // If explosion finish, Remove the current element from the iterator & list.
                iterator.remove();
                continue;
            }
        }
    }
 
    @Override
    public void draw(Canvas canvas)  {
        super.draw(canvas);
 
        for(ChibiCharacter chibi: chibiList)  {
            chibi.draw(canvas);
        }
 
        for(Explosion explosion: this.explosionList)  {
            explosion.draw(canvas);
        }
 
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
        ChibiCharacter chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
 
        Bitmap chibiBitmap2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi2);
        ChibiCharacter chibi2 = new ChibiCharacter(this,chibiBitmap2,300,150);
 
        this.chibiList.add(chibi1);
        this.chibiList.add(chibi2);
 
        this.gameThread = new GameThread(this,holder);
        this.gameThread.setRunning(true);
        this.gameThread.start();
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 
    }
 
    // Implements method of SurfaceHolder.Callback
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry= true;
        while(retry) {
            try {
                this.gameThread.setRunning(false);
 
                // Parent thread must wait until the end of GameThread.
                this.gameThread.join();
            }catch(InterruptedException e)  {
                e.printStackTrace();
            }
            retry= true;
        }
    }
 
}

Chạy lại trò chơi của bạn:

Xem phần tiếp theo tại đây.

vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!



Khóa học liên quan

Khóa học: Game