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

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

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

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

暫停
00:00 / 00:23
00:00
進(jìn)入全屏
50
    點(diǎn)擊按住可拖動(dòng)視頻

    游戲效果演示

    游戲動(dòng)畫其實(shí)就是將圖片資源逐幀逐幀地播放,只是在這部游戲中我們并不打算用圖片文件而是用程序代碼手繪畫面,因?yàn)槭鞘掷L所以畫面簡(jiǎn)單了些。好了!照例先定義一個(gè)父類,然后再定義其它的動(dòng)畫類并繼承父類。

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

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

    import android.graphics.*
    import com.bamboo.boxspacegame.AppGobal
    
    /**
     * 子彈擊中物體時(shí)的特效
     */
    class BulletEffect : BaseEffect() {
        private var currentFrame = 0
    
        companion object {
            private const val FRAME_COUNT = 15 // 動(dòng)畫的總幀數(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ù)當(dāng)前幀的編號(hào)繪制動(dòng)畫
         */
        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
            }
        }
    
        /**
         * 播放動(dòng)畫并設(shè)置動(dòng)畫播放的坐標(biāo)
         */
        fun play(x: Float, y: Float) {
            free = false
            this.x = x
            this.y = y
            this.currentFrame = 0
        }
    
    }

    當(dāng)子彈擊中目標(biāo)或擊在屏幕邊界的時(shí)候就開始播放彈痕動(dòng)畫。接著定義開始爆炸動(dòng)畫類BombEffect.kt

    import android.graphics.*
    import com.bamboo.boxspacegame.AppGobal
    
    /**
     * 爆炸動(dòng)畫特效
     */
    class BombEffect : BaseEffect() {
        private val paint = Paint()
        private var currentFrame = 1
        private var onFinished: (() -> Unit)? = null // 動(dòng)畫播放完畢后的回調(diào)函數(shù)
    
        companion object {
            const val FRAME_COUNT = 20 // 動(dòng)畫的總幀數(shù)
        }
    
        /**
         * 播放動(dòng)畫
         * @param onFinished 動(dòng)畫播放完畢后的回調(diào)函數(shù),默認(rèn)可以不傳
         */
        fun play(x: Float, y: Float, onFinished: (() -> Unit)? = null) {
            this.free = false
            this.x = x
            this.y = y
            this.currentFrame = 0
            this.onFinished = onFinished
        }
    
        /**
         * 直接在屏幕上繪制圖像,并不在游戲初始化時(shí)緩存
         */
        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)
            }
        }
    }

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

    import android.graphics.*
    import com.bamboo.boxspacegame.AppGobal
    
    /**
     * 瞬移的動(dòng)畫特效
     * 動(dòng)畫可以正序或倒序播放
     */
    class FlashEffect : BaseEffect() {
        private var isInvert: Boolean = false // 判斷動(dòng)畫是正序播放還是倒序播放
        private var currentFrame = 0
        private var onFinished: (() -> Unit)? = null // 動(dòng)畫播放完畢后的回調(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() }
                }
            }
        }
    
        /**
         * 播放瞬移動(dòng)畫
         * @param isInvert 是否倒置播放動(dòng)畫
         * @param onFinished 動(dòng)畫播放完畢后響應(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
        }
    }

    至此,游戲所需要的三個(gè)動(dòng)畫類就全部完成了?,F(xiàn)在我們要實(shí)現(xiàn)了個(gè)管理類,對(duì)這種特效類進(jì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()
        }
    }

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

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

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

    熱門課程推薦

    熱門資訊

    請(qǐng)綁定手機(jī)號(hào)

    x

    同學(xué)您好!

    您已成功報(bào)名0元試學(xué)活動(dòng),老師會(huì)在第一時(shí)間與您取得聯(lián)系,請(qǐng)保持電話暢通!
    確定