日々是好日~every day is a good day~

日常の中の非日常の備忘録

【Android Studio】背景を動かす

Android Studioで応用範囲の広いゲームのひな形みたいなものを作りたくてただ背景が動くだけのものを作ってみました
まずres/drawableに画像を用意
いつものように『いらすとや』さんからお借りしてます
www.irasutoya.com
次にactivity_main.xmlの編集
画面全体をSurfaceViewにします

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <SurfaceView
        android:id="@+id/surfaceview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0" />

</androidx.constraintlayout.widget.ConstraintLayout>

次にMainActivity.ktの編集

import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity

var SCREEN_WIDTH = 0
var SCREEN_HEIGHT = 0
var isRunning = false

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val surfaceView: SurfaceView = findViewById(R.id.surfaceview)
        PlayView(this, surfaceView)   //SurfaceViewのインスタンスを生成

        GetScreenSize(this)  //スクリーンサイズの取得
    }

    //スクリーンサイズの取得
    fun GetScreenSize(context: Context) {
        val vm: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val display = vm.defaultDisplay
        val metric = DisplayMetrics()
        display.getMetrics(metric)
        SCREEN_WIDTH = metric.widthPixels
        SCREEN_HEIGHT = metric.heightPixels
    }
}

// SurfaceViewを継承したクラス
class PlayView: SurfaceView, SurfaceHolder.Callback {
    private var surfaceHolder: SurfaceHolder? = null

    constructor(context: Context, surfaceView: SurfaceView) : super(context) {
        surfaceHolder = surfaceView.holder
        // コールバック
        surfaceHolder!!.addCallback(this)
    }

    override fun surfaceCreated(p0: SurfaceHolder) {
        val playgame = PlayGame(surfaceHolder!!, resources)
            //ゲームスタート
            isRunning = true
            playgame.start()
    }

    override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {

    }

    override fun surfaceDestroyed(p0: SurfaceHolder) {

    }
}

//ゲームのThreadクラス
class PlayGame:Thread{
    private var holder : SurfaceHolder
    private var resources : Resources
    private var backBitmap : Bitmap
    private var backPosx = 0
    private var backPosy = 0
    constructor(holder: SurfaceHolder, resources: Resources) {
        this.holder = holder
        this.resources = resources
        backBitmap = BitmapFactory.decodeResource(resources, R.drawable.sougen)

    }
    override fun run() {
        while(isRunning){
            if(holder == null) return
            val canvas = holder.lockCanvas()
            if(canvas != null){
                try {
                    synchronized(holder){
                        BackGround(canvas)   //背景を表示
                        //////// 新しい関数を追加 /////////
                    }
                }
                finally {
                    holder.unlockCanvasAndPost(canvas)
                }
            }
        }
    }
    private fun BackGround(canvas: Canvas){
        val backVelocity = 5   //背景の移動速度

        backPosx= backPosx - backVelocity
        if(backPosx < -backBitmap.width){
            backPosx = 0
        }
        canvas.drawBitmap(backBitmap,backPosx.toFloat(),backPosy.toFloat(),null)

        //背景をloop表示
        if(backPosx < -(backBitmap.width-SCREEN_WIDTH) ||
            backBitmap.width < SCREEN_WIDTH) {
            canvas.drawBitmap(backBitmap,(backPosx + backBitmap.width).toFloat(),
                backPosy.toFloat(),null)
            canvas.drawBitmap(backBitmap,(backPosx + backBitmap.width*2).toFloat(),
                backPosy.toFloat(),null)
        }
    }
}

あとは画面を横に固定します
everydayisagoodday.hatenadiary.com
実行すると

新しい機能を付けたいときは関数を作ってPlayGameクラスの新しい関数を追加のところで呼べばOKです