Archive for Juni 2015

Tugas SoftSkill 3 : Pengantar Teknologi Game (Puzzle)


Flowchart

Gambar 3.1 Flowchart
            Pertama kali saat program dijalankan, menu untuk memilih gambar akan muncul untuk memberikan pilihan kepada pengguna puzzle dengan gambar apa dan ukuran berapa yang ingin dipecahkan oleh pengguna. Kemudian setelah pengguna memilih gambar yang diinginkan beserta ukurannya, maka pengguna akan diarahkan ke dalam papan bermain puzzle. Timer akan menghitung mundur dari tiga sebelum puzzle di acak dari bentuk aslinya, sehingga pengguna punya waktu tiga detik untuk melihat wujud asli dari puzzle.
            Game tidak akan berhenti sebelum permainan diselesaikan oleh pemain atau pemain mengganti puzzle yang ingin dimainkan. Jika pemain menyelesaikan puzzle, Game akan memunculkan tampilan hasil bermain pemain.

Story Board
Gambar 3.2 Story Board
            Secara teknis program berjalan berawal dari menu kemudian berpindah ke papan bermain dan tampilan hasil bermain.

Rancangan Aplikasi
            Dalam pembuatan aplikasi, perancangan yang dilakukan penulis secara teknis terbagi menjadu dua yaitu, perancangan program atau fungsi program dan perancangan tampilan.

Rancangan Tampilan
            Permainan Puzzle yang penulis buat memiliki tiga buah tampilan, yaitu tampilan menu awal, tampilan papan bermain dan tampilan hasil bermain.

Tampilan Awal
Gambar 3.3 Tampilan Menu
            Pada tampilan awal pengguna akan dihadapkan dengan enam buah gambar yang sudah disiapkan sebagai bawaan aplikasi. Masing-masing gambar juga memiliki dimensi yang berbeda-beda. Dimensi gambar yang berbeda-beda ini mewakili tingkat kesulitan puzzle yang akan dimainkan oleh pemain. Ketika pemain sudah memilih, pemain akan diarahkan ke dalam papan bermain.

Tampilan Papan Bermain
Gambar 3.4 Tampilan Papan Bermain
            Dalam tabel papan bermain, pemain akan dihadapkan oleh gambar yang sudah dipilih pemain. Pemain dapat melihat potongan gambar tersebut dengan urutan yang benar selama tiga detik. Game akan menghitung mundur dan pada akhir hitungan potongan gambar akan teracak dan permainan pun dimulai. Setiap potongan gambar yang dipindahkan oleh pemain akan dihitung, sehingga di akhir pemain dapat melihat banyak langkah yang dibutuhkan oleh pemain untuk menyelesaikan gambar yang dimainkan.

Tampilan Menang
3.5 Tampilan Menang
            Pada tampilan hasil bermain, pemain akan melihat puzzle dengan urutan yang benar beserta jumlah langkah yang dibutuhkan oleh pemain untuk menyelesaikan puzzle tersebut.

Kode Program
            Untuk dapat menjalankan fungsi-fungsi dari permainan, dibutuhkan beberapa baris kode program yang dapat bereaksi sesuai dengan fungsi yang akan dijalankan. Beberapa baris program itupun dikelompokkan ke dalam masing-masing file yang disebut class dalam java, agar tidak tercampur baur antara fungsi yang satu dengan fungsi yang lain.

Application.java
public class Application extends android.app.Application{
 public Future<?> submitBackgroundTask(Runnable task) {
  return getBackgroundThreads().submit(task);
 }

 public <T> Future<T> submitBackgroundTask(Callable<T> task) {
  return getBackgroundThreads().submit(task);
 }

 public void onActivityDestroy(Activity activity) {
  activities.remove(activity);
  if (activities.isEmpty())
   onTerminate();
 }


 protected ExecutorService getBackgroundThreads() {
  if (null == backgroundThreads)
   backgroundThreads = Executors.newCachedThreadPool();
  return backgroundThreads;
 }


            Pada saat pemain memilih gambar, maka gambar tersebut harus dipanggil ke dalam papan bermain dari folder tempat gambar tersebut disimpan. Selain dipanggil, gambar tersebut pun harus ditampilkan dalam papan bermain. Untuk itu kelas ini akan memanggil dan menampilkan gambar yang dipilh oleh pemain.

ImageConverter.java
public class ImageConverter implements Runnable{
  }
  protected BitmapFactory.Options prepareOptions() throws IOException  {
   InputStream pictureData = null;
   try
   {
    pictureData = openInputStream();
    BitmapFactory.Options bitmapInfo = new  BitmapFactory.Options();
    bitmapInfo.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(pictureData, null, bitmapInfo);
    pictureData.close();
    pictureData = null;
    int maxBitmapSize = bitmapInfo.outWidth;
    if (maxBitmapSize < bitmapInfo.outHeight)
     maxBitmapSize = bitmapInfo.outHeight;
    if (maxBitmapSize > maxFrameDim && (0 > maxFrameDim * 2 || maxBitmapSize >= maxFrameDim * 2))
    {
     bitmapInfo.inJustDecodeBounds = false;
     bitmapInfo.inSampleSize = (maxBitmapSize - 1) / maxFrameDim + 1;
     return bitmapInfo;
    }
    else
     return null;
   }
   finally   {
    if (null != pictureData)
     try { pictureData.close(); } catch (Exception ignored) {}
   }
  }
 
  protected InputStream openInputStream() throws FileNotFoundException
  {
   if (null != imageURI)
    return context.getContentResolver().openInputStream(imageURI);
   else
    return context.getResources().openRawResource(imageResource);
  }
  public void setImageId(Serializable imageId)
  {
   if (imageId instanceof Integer)
   {
    this.imageResource = (Integer)imageId;
    this.imageURI = null;
   }
   else
    setImageURI(Uri.fromFile(ImageSource.imageFileForId((String)imageId, context)));
  }

            Pada kelas ini, gambar yang dipilih sebelumnya akan di convert ke dalam format bitmap pada canvas android. Tujuannya supaya gambar pada sumber tidak berubah dan dapat diproses dalam program menjadi beberapa potongan.

Board.java
public class Game implements MoveListener, TileOnTargetListener{
 public void updateImageSize(Context context)
       throws ImageProcessingException
 {
  if (null == selectedImageId)
   throw new IllegalStateException("No image selected");
  try
  {
//   BitmapFactory.Options request = new BitmapFactory.Options();
//   request.inJustDecodeBounds = true;
//   BitmapFactory.decodeResource(context.getResources(), selectedImageId, request);
//   if (0 <= request.outWidth && 0 <= request.outHeight)
   Bitmap fullImage = loadFullImage(context);
   if (null != fullImage)
    imageAspectRatio = // (float)request.outWidth / request.outHeight;
       (float)fullImage.getWidth() / fullImage.getHeight();
   else
    imageAspectRatio = Float.NaN;
  }
  catch (Resources.NotFoundException e)
  {
   throw new ImageProcessingException("Resource not found: 0x"
     + Integer.toHexString((Integer)selectedImageId), e);
  }
//  if (null == fullImage)
  if (Float.NaN == imageAspectRatio)
   throw new ImageProcessingException("Error loading image "
     + selectedImageId);
 }

 public void loadImage(final Context context)
       throws ImageProcessingException
 {
  if (null == selectedImageId)
   throw new IllegalStateException("No image selected");
  if (0 > tileHeight || 0 > tileWidth)
   throw new IllegalStateException("Target size is not set");
  // load and scale the image
  final int boardSize = board.getSize();
  try
  {
   Bitmap fullImage = loadFullImage(context);
   if (null == fullImage)
    throw new ImageProcessingException("Error loading image "
      + selectedImageId);
   scaledImage = Bitmap.createScaledBitmap(
     fullImage, tileWidth * boardSize, tileHeight * boardSize, false);
  }
  catch (Resources.NotFoundException e)
  {
   throw new ImageProcessingException("Resource not found: 0x"
     + Integer.toHexString((Integer)selectedImageId), e);
  }
  // slice the image
  board.forEachTile(new Board.TileHandler() {
   public void processTile(Tile tile)
   {
    Drawable image;
    if (0 == tile.getNumber())
     image = new ColorDrawable(context.getResources().getColor(R.color.blank_tile));
    else
    {
     Bitmap slice = Bitmap.createBitmap(
        scaledImage,
        tileWidth * tile.getTargetColumn(),
        tileHeight * tile.getTargetRow(),
        tileWidth,
        tileHeight
       );
     image = new BitmapDrawable(context.getResources(), slice);
    }
    tile.setDrawable(image);
   }
  });

            Gambar yang sudah di convert sebelumnya akan tampilkan dalam bentuk bitmap sementara, kemudian dipotong serta di acak agar dapat dimainkan oleh pemain. Dalam papan bermain juga terdapat beberapa menu untuk kembali ke menu awal, mengacak kembali puzzle, juga pilihan level berdasarkan dimensi gambar.

Move.java
public enum Move{
 UP(false, -1), LEFT(true, -1), DOWN(false, 1), RIGHT(true, 1);
 public boolean isHorizontal() {
  return horizontal;
 }
 public boolean isVertical() {
  return !horizontal;
 }
 public int getAmount() {
  return amount;
 }

 @Override
 public String toString() {
  return name().toLowerCase() + " move";
 }
 private Move(boolean horizontal, int amount) {
  this.horizontal = horizontal;
  this.amount = amount;
 }
 private boolean horizontal;
 private int amount; }

            Potongan gambar yang sudah terbentuk harus dapat digerakkan agar dapat disusun oleh pemain. Selain digerakkan, potongan gambar perlu dihitung agar di akhir permainan pemain dapat mengetahui berapa banyak langkah yang diperlukan oleh pemain untuk menyelesaikan puzzlenya. Kelas ini berfungsi untuk mengaktifkan fungsi tersebut.

3.3.2.5 YouWin.java
public class YouWin extends Activity implements OnClickListener{
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  TextView stats = (TextView)findViewById(R.id.text_puzzle_solved);
  final Intent intent = getIntent();
  final int moveCount = intent.getIntExtra(EXTRA_MOVE_COUNT, 0);
  final String template = getResources().getString(R.string.text_puzzle_solved);
  Formatter format = new Formatter().format(template, moveCount, 1 == moveCount ? "" : "s");
  stats.setText((CharSequence)format.out());
  if (intent.hasExtra(ImageSelection.EXTRA_SELECTED_IMAGE_ID_KEY))  {
   initImageView(intent.getSerializableExtra(ImageSelection.EXTRA_SELECTED_IMAGE_ID_KEY));
   findViewById(R.id.congratulations_picture).setOnClickListener(this);
  }
  else  {
   final View button = findViewById(R.id.next_puzzle_button);
   button.setVisibility(View.VISIBLE);
   button.setOnClickListener(this);
  }
  findViewById(R.id.text_puzzle_blurb_2).setOnClickListener(
    new OnClickListener() {
     @Override
     public void onClick(View v)     {
      final Uri url = Uri.parse(getResources().getString(R.string.text_puzzle_blurb_url));
      Intent call = new Intent(Intent.ACTION_VIEW, url);
      startActivity(call);     }    }    ); }

            Pada akhir permainan, bila pemain dapat menyelesaikan puzzle maka akan terlihat gambar puzzle yang pemain selesaikan serta jumlah langkah yang diperlukan oleh pemain untuk menyelesaikan puzzle. Sebuah dialog akan muncul untuk menanyakan apakah pemain ingin bermain kembali atau tidak.



Implementasi
            Pada tahap ini, program sudah dapat berjalan dengan segala fungsinya. Untuk mengoreksi kesalahan dan bug pada program, maka diperlukan percobaan dalam menjalankan program.

Menu Gambar
Gambar 3.6 Menu
            Dalam tampilan ini dapat dilihat bahwa program menampilkan enam buah gambar yang berbeda serta dalam dimensi yang berbeda. Dimensi yang berbeda menunjukkan tingkat kesulitan yang berbeda dari tiap puzzle. Pemain juga dapat memilih sendiri gambar yang ingin dipecahkan dari folder penyimpanan gambar device milik pemain.

Papan Bermain
Gambar 3.7 Papan Bermain
            Gambar yang dipilih akan diacak dalam waktu tiga detik setelah potongan gambar dengan urutan yang sebenarnya ditampilkan. Setelah diacak, puzzle baru dapat bereaksi akan sentuhan dari pemain. Potongan puzzle yang dapat bergerak hanya yang bersebrangan langsung dengan ruang kosong dari puzzle, sehingga  pemain harus dapat merapihkan potongan gambar sesuai dengan urutan aslinya dengan keterbatasan ruang gerak. Permainan hanya akan berakhir jika pemain memilih untuk kembali ke menu awal atau menyelesaikan puzzle.

Output Menang
Gambar 3.8 Menang

            Permainan yang berakhir dengan cara pemain menyelesaikan puzzle, akan menampilkan skor yang berbentuk jumlah perpindahan potongan gambar yang dilakukan oleh pemain.
Kamis, 18 Juni 2015
Posted by San

Popular Post

Blogger templates

Blog Archive

ReeCoder. Diberdayakan oleh Blogger.

Followers

Gunadarma Headline News

Me on Google+

- Copyright © Ree San -Metrominimalist- Powered by Blogger - Designed by Johanes Djogan -