激情六月丁香婷婷|亚洲色图AV二区|丝袜AV日韩AV|久草视频在线分类|伊人九九精品视频|国产精品一级电影|久草视频在线99|在线看的av网址|伊人99精品无码|午夜无码视频在线

高校合作1:010-59833514 ?咨詢電話:400-810-1418 服務(wù)與監(jiān)督電話:400-810-1418轉(zhuǎn)接2

Android游戲教程:空間大戰(zhàn) - 動畫特效

發(fā)布時間:2023-11-30 12:48:16 瀏覽量:249次

暫停
00:00 / 00:23
00:00
進入全屏
50
    點擊按住可拖動視頻

    游戲效果演示

    游戲動畫其實就是將圖片資源逐幀逐幀地播放,只是在這部游戲中我們并不打算用圖片文件而是用程序代碼手繪畫面,因為是手繪所以畫面簡單了些。好了!照例先定義一個父類,然后再定義其它的動畫類并繼承父類。

    import android.graphics.Canvas
    
    abstract class BaseEffect {
        // 動畫播放的中心坐標
        protected var x: Float = 0f
        protected var y: Float = 0f
        var free: Boolean = true
    
        abstract fun draw(canvas: Canvas)
    }

    定義完父類后就可以定義實際的子類了,我們先定義子彈的彈痕類BulletEffect.kt

    import android.graphics.*
    import com.bamboo.boxspacegame.AppGobal
    
    /**
     * 子彈擊中物體時的特效
     */
    class BulletEffect : BaseEffect() {
        private var currentFrame = 0
    
        companion object {
            private const val FRAME_COUNT = 15 // 動畫的總幀數(shù)
    
            /**
             * 初始化彈痕的Bitmap并緩存
             */
            fun init() {
                val paint = Paint()
                paint.color = Color.WHITE
                paint.style = Paint.Style.FILL
                repeat(FRAME_COUNT) {
                    val bmp = Bitmap.createBitmap(
                        AppGobal.unitSize.toInt(),
                        AppGobal.unitSize.toInt(),
                        Bitmap.Config.ARGB_8888
                    )
                    Canvas(bmp).apply {
                        val unit = AppGobal.unitSize / 2f
                        paint.alpha = 255 - (255 / FRAME_COUNT * it)
                        paint.shader = RadialGradient(
                            unit, unit, unit + 0.1f,
                            intArrayOf(Color.WHITE, Color.TRANSPARENT), null,
                            Shader.TileMode.CLAMP
                        )
                        this.drawCircle(unit, unit, unit, paint)
                    }
                    AppGobal.bmpCache.put("bulletEffect_$it", bmp)
                }
            }
        }
    
        /**
         * 根據(jù)當前幀的編號繪制動畫
         */
        override fun draw(canvas: Canvas) {
            val bmp = AppGobal.bmpCache["bulletEffect_$currentFrame"]
            val ex = x - AppGobal.unitSize / 2
            val ey = y - AppGobal.unitSize / 2
            canvas.drawBitmap(bmp, ex, ey, null)
            currentFrame++
            if (currentFrame >= FRAME_COUNT) {
                currentFrame = 0
                free = true
            }
        }
    
        /**
         * 播放動畫并設(shè)置動畫播放的坐標
         */
        fun play(x: Float, y: Float) {
            free = false
            this.x = x
            this.y = y
            this.currentFrame = 0
        }
    
    }

    當子彈擊中目標或擊在屏幕邊界的時候就開始播放彈痕動畫。接著定義開始爆炸動畫類BombEffect.kt

    import android.graphics.*
    import com.bamboo.boxspacegame.AppGobal
    
    /**
     * 爆炸動畫特效
     */
    class BombEffect : BaseEffect() {
        private val paint = Paint()
        private var currentFrame = 1
        private var onFinished: (() -> Unit)? = null // 動畫播放完畢后的回調(diào)函數(shù)
    
        companion object {
            const val FRAME_COUNT = 20 // 動畫的總幀數(shù)
        }
    
        /**
         * 播放動畫
         * @param onFinished 動畫播放完畢后的回調(diào)函數(shù),默認可以不傳
         */
        fun play(x: Float, y: Float, onFinished: (() -> Unit)? = null) {
            this.free = false
            this.x = x
            this.y = y
            this.currentFrame = 0
            this.onFinished = onFinished
        }
    
        /**
         * 直接在屏幕上繪制圖像,并不在游戲初始化時緩存
         */
        override fun draw(canvas: Canvas) {
            paint.color = Color.WHITE
            paint.strokeWidth = 2f
            val inc = AppGobal.unitSize / FRAME_COUNT
            currentFrame++
            if (currentFrame >= FRAME_COUNT) {
                currentFrame = 0
                free = true
                onFinished?.let { it() }
            } else {
                paint.style = if (currentFrame >= FRAME_COUNT / 2) Paint.Style.STROKE
                else Paint.Style.FILL
                canvas.drawCircle(x, y, inc * currentFrame, paint)
            }
        }
    }

    接著實現(xiàn)游戲的瞬移動畫類FlashEffect.kt

    import android.graphics.*
    import com.bamboo.boxspacegame.AppGobal
    
    /**
     * 瞬移的動畫特效
     * 動畫可以正序或倒序播放
     */
    class FlashEffect : BaseEffect() {
        private var isInvert: Boolean = false // 判斷動畫是正序播放還是倒序播放
        private var currentFrame = 0
        private var onFinished: (() -> Unit)? = null // 動畫播放完畢后的回調(diào)函數(shù)
    
        companion object {
            private const val FRAME_COUNT = 30
    
            fun init() {
                val unit = AppGobal.unitSize / 2
                val paint = Paint()
                paint.color = Color.WHITE
                paint.style = Paint.Style.FILL_AND_STROKE
                paint.strokeWidth = 1f
                repeat(FRAME_COUNT) {
                    // 繪制瞬移的各幀圖像
                    val bmp = Bitmap.createBitmap(
                        (AppGobal.unitSize * 2).toInt(),
                        (AppGobal.unitSize * 2).toInt(),
                        Bitmap.Config.ARGB_8888
                    )
                    Canvas(bmp).apply {
                        paint.shader = RadialGradient(
                            unit, unit, unit,
                            intArrayOf(
                                Color.parseColor("#33FFFFFF"),
                                Color.parseColor("#66FFFFFF"),
                                Color.WHITE,
                            ), null,
                            Shader.TileMode.CLAMP
                        )
                        val step = (unit / FRAME_COUNT) * it
                        this.drawCircle(unit, unit, unit - step, paint)
                        paint.shader = RadialGradient(
                            unit, unit, unit,
                            intArrayOf(Color.WHITE, Color.parseColor("#33FFFFFF")), null,
                            Shader.TileMode.CLAMP
                        )
                        this.drawOval(
                            unit - (unit + step), unit - 2,
                            unit + (unit + step) - 1, unit + 2,
                            paint
                        )
                        this.drawOval(unit - 1, unit - 6, unit + 1, unit + 6, paint)
                    }
                    AppGobal.bmpCache.put(AppGobal.BMP_FLASH + "_$it", bmp)
                }
            }
        }
    
        override fun draw(canvas: Canvas) {
            val bmp = AppGobal.bmpCache[AppGobal.BMP_FLASH + "_$currentFrame"]
            canvas.drawBitmap(bmp, x, y, null)
            if (isInvert) {
                currentFrame--
                if (currentFrame < 0) {
                    currentFrame = 15
                    free = true
                    onFinished?.let { it() }
                }
            } else {
                currentFrame++
                if (currentFrame >= FRAME_COUNT) {
                    currentFrame = 0
                    free = true
                    onFinished?.let { it() }
                }
            }
        }
    
        /**
         * 播放瞬移動畫
         * @param isInvert 是否倒置播放動畫
         * @param onFinished 動畫播放完畢后響應(yīng)
         */
        fun play(x: Float, y: Float, isInvert: Boolean = false, onFinished: (() -> Unit)? = null) {
            this.x = x
            this.y = y
            this.free = false
            this.currentFrame = if (isInvert) FRAME_COUNT - 1 else 0
            this.isInvert = isInvert
            this.onFinished = onFinished
        }
    }

    至此,游戲所需要的三個動畫類就全部完成了?,F(xiàn)在我們要實現(xiàn)了個管理類,對這種特效類進行統(tǒng)一管理。EffectManager.kt

    import android.graphics.Canvas
    
    /**
     * 特效管理類
     */
    object EffectManager {
        private val listEffect = mutableListOf<BaseEffect>()
    
        @Synchronized
        private inline fun <reified T : BaseEffect> obtain(t: T): BaseEffect {
            val effect = listEffect.find {
                it.free && (it is T)
            }
            return effect ?: t.apply { listEffect += this }
        }
    
        fun obtainBomb(): BombEffect {
            return obtain(BombEffect()) as BombEffect
        }
    
        fun obtainFlash(): FlashEffect {
            return obtain(FlashEffect()) as FlashEffect
        }
    
        fun obtainBullet(): BulletEffect {
            return obtain(BulletEffect()) as BulletEffect
        }
    
        fun draw(canvas: Canvas) {
            try {
                listEffect.filter { !it.free }.forEach { it.draw(canvas) }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        
        @Synchronized
        fun release() {
            listEffect.clear()
        }
    }

    下一篇我們就要實現(xiàn)游戲的關(guān)卡類了。

    傳送門:Android游戲教程:空間大戰(zhàn)

    如果對我的文章感興趣或有疑問的話可以加我的公眾號或Q群聊:口袋里的安卓

    熱門課程推薦

    熱門資訊

    請綁定手機號

    x

    同學(xué)您好!

    您已成功報名0元試學(xué)活動,老師會在第一時間與您取得聯(lián)系,請保持電話暢通!
    確定