安卓小游戏:飞机大战

news2025/1/12 3:07:00

安卓小游戏:飞机大战

前言

前面写了十二篇自定义view的博客,说实话写的还是有点无聊了,最近调整了一下,觉得还是要对开发有热情,就写了点小游戏,现在抽时间把博客也写一写,希望读者喜欢。

需求

这里就是飞机大战啊,很多人小时候都玩过,我这也比较简单还原了一下。核心思想如下:

  • 1,载入界面配置,设置游戏信息
  • 2,载入精灵配置,获取飞机、子弹、敌人掩图
  • 3,启动手势控制逻辑
  • 4,启动游戏controller,定时刷新处理逻辑

效果图

效果图还阔以吧,就是掩图马虎了,直接再Android Studio里面找的vector的image,玩起来还是有点小时候的感觉。

airplane

代码

import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.silencefly96.module_views.R
import java.lang.ref.WeakReference
import kotlin.math.pow
import kotlin.math.sqrt


/**
 * 飞机大战 GameView
 *
 * 1,载入界面配置,设置游戏信息
 * 2,载入精灵配置,获取飞机、子弹、敌人掩图
 * 3,启动手势控制逻辑
 * 4,启动游戏controller,定时刷新处理逻辑
 *
 * @author silence
 * @date 2023-01-17
 */
class AirplaneFightGameView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
): View(context, attributeSet, defStyleAttr) {

    companion object{

        // 游戏更新间隔,一秒20次
        const val GAME_FLUSH_TIME = 50L
        // 敌人添加隔时间
        const val ADD_ENEMY_TIME = 1000L
        // 敌人更新隔时间
        const val UPDATE_ENEMY_TIME = 200L
        // 敌人移动距离
        const val ENEMY_MOVE_DISTANCE = 50
        // 子弹添加隔时间
        const val ADD_BULLET_TIME = 150L
        // 子弹更新隔时间
        const val UPDATE_BULLET_TIME = 100L
        // 子弹移动距离
        const val BULLET_MOVE_DISTANCE = 50

        // 碰撞间隔
        const val COLLISION_DISTANCE = 100

        // 距离计算公式
        fun getDistance(x1: Int, y1: Int, x2: Int, y2: Int): Float {
            return sqrt(((x1 - x2).toDouble().pow(2.0)
                    + (y1 - y2).toDouble().pow(2.0)).toFloat())
        }
    }

    // 默认生命值大小
    private val mDefaultLiveSize: Int

    // 得分
    private var mScore: Int = 0

    // 飞机
    private val mAirPlane: Sprite = Sprite(0, 0)
    private val mAirPlaneMask: Bitmap?

    // 子弹序列
    private val mBulletList = ArrayList<Sprite>()
    private val mBulletMask: Bitmap?

    // 敌人序列
    private val mEnemyList = ArrayList<Sprite>()
    private val mEnemyMask: Bitmap?

    // 游戏控制器
    private val mGameController = GameController(this)

    // 画笔
    private val mPaint = Paint().apply {
        color = Color.WHITE
        strokeWidth = 3f
        style = Paint.Style.STROKE
        flags = Paint.ANTI_ALIAS_FLAG
        textAlign = Paint.Align.CENTER
        textSize = 30f
    }

    // 上一个触摸点X的坐标
    private var mLastX = 0f

    init {
        // 读取配置
        val typedArray =
            context.obtainStyledAttributes(attributeSet, R.styleable.AirplaneFightGameView)

        mDefaultLiveSize =
            typedArray.getInteger(R.styleable.AirplaneFightGameView_liveSize, 3)

        // 得到的Bitmap为空
//        var resourceId =
//        typedArray.getResourceId(R.styleable.AirplaneFightGameView_airplane, 0)
//        mAirPlaneMask = if (resourceId != 0) {
//            BitmapFactory.decodeResource(resources, resourceId)
//        }else null

        // 注意Drawable也有类型
//        var drawable = typedArray.getDrawable(R.styleable.AirplaneFightGameView_airplane)
//        mAirPlaneMask = (drawable as BitmapDrawable).bitmap     //vector的xml不是BitmapDrawable
//        mAirPlaneMask = (drawable as VectorDrawable).toBitmap() //需要版本支持

        // 飞机掩图
        var drawable = typedArray.getDrawable(R.styleable.AirplaneFightGameView_airplane)
        mAirPlaneMask = if (drawable != null) drawableToBitmap(drawable, 2) else null

        // 子弹掩图
        drawable = typedArray.getDrawable(R.styleable.AirplaneFightGameView_bullet)
        mBulletMask = if (drawable != null) drawableToBitmap(drawable) else null

        // 敌人掩图
        drawable = typedArray.getDrawable(R.styleable.AirplaneFightGameView_enemy)
        mEnemyMask = if (drawable != null) drawableToBitmap(drawable, 2) else null

        typedArray.recycle()
    }

    private fun drawableToBitmap(drawable: Drawable, size: Int = 1): Bitmap? {
        val w = drawable.intrinsicWidth * size
        val h = drawable.intrinsicHeight * size
        val config = Bitmap.Config.ARGB_8888
        val bitmap = Bitmap.createBitmap(w, h, config)
        //注意,下面三行代码要用到,否则在View或者SurfaceView里的canvas.drawBitmap会看不到图
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, w, h)
        drawable.draw(canvas)
        return bitmap
    }

    // 完成测量开始游戏
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        // 开始游戏
        load(w, h)
    }

    // 加载
    private fun load(w: Int, h: Int) {
        mGameController.removeMessages(0)
        // 设置好飞机位置,坐标未中心坐标,方便计算碰撞
        mAirPlane.bitmap = mAirPlaneMask
        mAirPlane.live = mDefaultLiveSize
        mAirPlane.posX = w / 2 - mAirPlaneMask!!.width / 2
        mAirPlane.posY = h - mAirPlaneMask.height / 2 - 50
        mGameController.sendEmptyMessageDelayed(0, GAME_FLUSH_TIME)
    }

    // 重新加载
    private fun reload(w: Int, h: Int) {
        mGameController.removeMessages(0)
        // 清空界面
        mBulletList.clear()
        mEnemyList.clear()
        // 重置好飞机位置、生命值、得分
        mScore = 0
        mAirPlane.live = mDefaultLiveSize
        mAirPlane.posX = w / 2 - mAirPlaneMask!!.width / 2
        mAirPlane.posY = h - mAirPlaneMask.height / 2 - 50
        mGameController.isGameOver = false
        mGameController.sendEmptyMessageDelayed(0, GAME_FLUSH_TIME)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
            getDefaultSize(0, heightMeasureSpec))
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 绘制顶部信息
        canvas.drawText("生命值:${mAirPlane.live}, 当前得分:$mScore",
            (width / 2).toFloat(), 50f, mPaint)

        // 绘制敌人
        for (enemy in mEnemyList) {
            canvas.drawBitmap(mEnemyMask!!,
                enemy.posX.toFloat() - mEnemyMask.width / 2,
                enemy.posY.toFloat() - mEnemyMask.height / 2, mPaint)
        }

        // 绘制子弹
        for (bullet in mBulletList) {
            canvas.drawBitmap(mBulletMask!!,
                bullet.posX.toFloat()- mBulletMask.width / 2,
                bullet.posY.toFloat()- mBulletMask.height / 2, mPaint)
        }

        // 绘制飞机
        canvas.drawBitmap(mAirPlaneMask!!,
            mAirPlane.posX.toFloat() - mAirPlaneMask.width / 2,
            mAirPlane.posY.toFloat() - mAirPlaneMask.height / 2, mPaint)
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                mLastX = event.x
            }
            MotionEvent.ACTION_MOVE -> {
                val len = event.x - mLastX
                val preX = mAirPlane.posX + len
                if (preX > mAirPlaneMask!!.width / 2 &&
                        preX < (width - mAirPlaneMask.width / 2)) {
                    mAirPlane.posX += len.toInt()
                    invalidate()
                }
                mLastX = event.x
            }
            MotionEvent.ACTION_UP -> {}
        }
        return true
    }

    private fun gameOver() {
        AlertDialog.Builder(context)
            .setTitle("继续游戏")
            .setMessage("请点击确认继续游戏")
            .setPositiveButton("确认") { _, _ -> reload(width, height) }
            .setNegativeButton("取消", null)
            .create()
            .show()
    }

    // kotlin自动编译为Java静态类,控件引用使用弱引用
    class GameController(view: AirplaneFightGameView): Handler(Looper.getMainLooper()){
        // 控件引用
        private val mRef: WeakReference<AirplaneFightGameView> = WeakReference(view)
        // 子弹更新频率限制
        private var bulletCounter = 0
        // 子弹出现频率控制
        private var bulletUpdateCounter = 0
        // 敌人更新频率控制
        private var enemyCounter = 0
        // 敌人出现频率控制
        private var enemyUpdateCounter = 0
        // 游戏结束标志
        internal var isGameOver = false

        override fun handleMessage(msg: Message) {
            mRef.get()?.let { gameView ->
                // 移动已有子弹
                bulletCounter++
                if (bulletCounter == (UPDATE_BULLET_TIME / GAME_FLUSH_TIME).toInt()) {
                    var mark = -1
                    for (i in 0 until gameView.mBulletList.size) {
                        val bullet = gameView.mBulletList[i]
                        bullet.posY -= BULLET_MOVE_DISTANCE
                        // 子弹出界
                        if (bullet.posY < 0) mark = i
                    }

                    // 移除出界子弹
                    if (mark >= 0) gameView.mBulletList.remove(gameView.mBulletList[mark])

                    bulletCounter = 0
                }

                // 移动敌人,并验证碰撞
                enemyUpdateCounter++
                if (enemyUpdateCounter == (UPDATE_ENEMY_TIME / GAME_FLUSH_TIME).toInt()) {
                    // 可能同时有子弹和敌人碰撞
                    val removeEnemyList = ArrayList<Sprite>()
                    val removeBulletList = ArrayList<Sprite>()
                    // 敌人和飞机碰撞标志
                    var mark = -1
                    for (i in 0 until gameView.mEnemyList.size) {
                        val enemy = gameView.mEnemyList[i]
                        enemy.posY += ENEMY_MOVE_DISTANCE

                        // 验证和子弹碰撞
                        for (j in 0 until gameView.mBulletList.size) {
                            val bullet = gameView.mBulletList[j]
                            if (getDistance(bullet.posX, bullet.posY, enemy.posX, enemy.posY)
                                <= COLLISION_DISTANCE) {
                                // 发生碰撞
                                removeEnemyList.add(enemy)
                                removeBulletList.add(bullet)
                                gameView.mScore++
                            }
                        }

                        //验证和飞机碰撞
                        if (getDistance(gameView.mAirPlane.posX, gameView.mAirPlane.posY,
                                enemy.posX, enemy.posY)
                            <= COLLISION_DISTANCE) {
                            // 发生碰撞
                            mark = i
                            if (--gameView.mAirPlane.live <= 0) {
                                isGameOver = true
                            }
                        }
                    }

                    // 统一移除
                    for (enemy in removeEnemyList) gameView.mEnemyList.remove(enemy)
                    for (bullet in removeBulletList) gameView.mBulletList.remove(bullet)
                    if (mark >= 0) gameView.mEnemyList.remove(gameView.mEnemyList[mark])

                    enemyUpdateCounter = 0
                }

                enemyCounter++
                if (enemyCounter == (ADD_ENEMY_TIME / GAME_FLUSH_TIME).toInt()) {
                    // 随机生成一个敌人
                    val x = (gameView.mEnemyMask!!.width / 2 +
                            Math.random() * (gameView.width - gameView.mEnemyMask.width)).toInt()
                    gameView.mEnemyList.add(
                        Sprite(x, gameView.mEnemyMask.height / 2, 1, gameView.mEnemyMask))

                    enemyCounter = 0
                }

                bulletUpdateCounter++
                if (bulletUpdateCounter == (ADD_BULLET_TIME / GAME_FLUSH_TIME).toInt()) {
                    // 添加新子弹,横向在飞机上居中
                    gameView.mBulletList.add(Sprite(gameView.mAirPlane.posX,
                        gameView.mAirPlane.posY, 1, gameView.mBulletMask))

                    bulletUpdateCounter = 0
                }

                // 循环发送消息,刷新页面
                gameView.invalidate()
                if (!isGameOver) {
                    gameView.mGameController.sendEmptyMessageDelayed(0, GAME_FLUSH_TIME)
                }else {
                    gameView.gameOver()
                }
            }
        }
    }

    // 坐标使用中心坐标
    data class Sprite(var posX: Int, var posY: Int, var live: Int = 1, var bitmap: Bitmap? = null)

    /**
     * 供外部回收资源
     */
    fun recycle()  {
        mAirPlaneMask?.recycle()
        mBulletMask?.recycle()
        mEnemyMask?.recycle()
        mGameController.removeMessages(0)
    }
}

对应style配置

res -> values -> airplane_fight_game_view_style.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name ="AirplaneFightGameView">
        <attr name="liveSize" format="integer"/>
        <attr name="airplane" format="reference"/>
        <attr name="bullet" format="reference"/>
        <attr name="enemy" format="reference"/>
    </declare-styleable>
</resources>

三个掩图也给一下吧,当然你找点好看的图片代替下会更好!

res -> drawable -> ic_airplane.xml

<vector android:height="24dp" android:tint="#01A5FD"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M22,16v-2l-8.5,-5V3.5C13.5,2.67 12.83,2 12,2s-1.5,0.67 -1.5,1.5V9L2,14v2l8.5,-2.5V19L8,20.5L8,22l4,-1l4,1l0,-1.5L13.5,19v-5.5L22,16z"/>
</vector>

res -> drawable -> ic_bullet.xml

<vector android:height="24dp" android:tint="#6F6A6A"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
</vector>

res -> drawable -> ic_enemy.xml

<vector android:height="24dp" android:tint="#DB172F"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M5,16c0,3.87 3.13,7 7,7s7,-3.13 7,-7v-4L5,12v4zM16.12,4.37l2.1,-2.1 -0.82,-0.83 -2.3,2.31C14.16,3.28 13.12,3 12,3s-2.16,0.28 -3.09,0.75L6.6,1.44l-0.82,0.83 2.1,2.1C6.14,5.64 5,7.68 5,10v1h14v-1c0,-2.32 -1.14,-4.36 -2.88,-5.63zM9,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM15,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
</vector>

主要问题

下面简单讲讲吧。

资源加载

这里用了styleable来配置游戏所需的资源,关于styleable我前面转载了一篇博文,别人写的很好,我就不再赘述。在init函数里面加载了生命值和掩图的资源id,注意这里没对id验证,如果没有设置或者设置不对可能会闪退,但是我这小游戏你不设置也没必要玩。。

掩图加载

这里我需要通过资源id拿到掩图资源,并转化为bitmap,这里踩了挺多坑。首先我是通过BitmapFactory对拿到的resourceId直接decode,结果拿到的bitmap为空,为此我还调试了一下,也不好确定原因,原因在后面也出现了,就是我这用的是vector的资源,并不能转换为BitmapDrawable,拿不到bitmap。后面还试了拿到Drawable,强制转换成BitmapDrawable拿到bitmap,也是不行,转成VectorDrawable需要改最低的api,最后还是借助canvas拿到的bitmap。

加载游戏

我这里是在onSizeChanged里面开始的,onSizeChanged会在第一次onMeasure后调用(前提是尺寸不发生变化),这里可以拿到控件宽高,正好对游戏进行一些配置,并发送空消息给handler,开启定时刷新。

游戏逻辑

onSizeChanged后开启定时刷新,游戏逻辑写在handler里就可以了,还可以根据刷新频率稍微控制下飞机、子弹、敌人的频率,我这里用了很多控制变量,当然小游戏可以这么写,复杂点的还是整理下吧。

游戏逻辑无非就是移动、碰撞、死亡几个,很简单,看代码就行,不多讲。这里稍稍注意下对列表数据的移除,我这里写的也不是很好,应该用iterator去移除的。

飞机移动逻辑

这里飞机移动逻辑和游戏逻辑分离了,直接在onTouchEvent中移动飞机,并通过invalidate刷新。飞机移动就没有必要和游戏刷新频率有关了吧,直接invalidate看起来舒服点。

画面绘制

画面绘制没得说,只要把飞机、子弹、敌人绘制出来就行了,逻辑和绘制分离。一开始我还想着又怎么移动,又怎么绘制,使用动画移动子弹什么的,太复杂了,反而不现实。

资源回收

这里用到了bitmap,最好要做下bitmap的回收。

想法的失误

一开始我是想把飞机、子弹、敌人当成控件,游戏当成viewgroup的,然后对控件进行操作,面向对象嘛,也许有道理,但是为什么不直接使用ondraw进行绘制,性能都更好一些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/331802.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

渲染速度特别慢,使用云渲染会快多少?

设计师在使用软件制作效果图和动画师在制作动画时&#xff0c;其中有一个比较关键的环节就是渲染成像&#xff0c;渲染的效率主要跟使用的电脑显卡或CPU性能有关&#xff0c;如果性能太低&#xff0c;渲染的速度会很慢&#xff0c;拉长了项目整体的交付周期&#xff0c;云渲染速…

反转链表的两种方法

大家好&#xff0c;今天和大家分享的是反转链表的两种方法&#xff0c;第一种是用泛型编程里面的STL&#xff0c;第二种是利用多个指针进行操作&#xff0c;小孩子才做选择&#xff0c;建议两个都学。我们往下看&#xff1a;一.使用vector容器ps&#xff1a;该方法对内存的需求…

LeetCode刷题--- 430. 扁平化多级双向链表(双指针)

文章目录一、编程题&#xff1a;430. 扁平化多级双向链表&#xff08;双指针&#xff09;1.题目描述2.示例1&#xff1a;3.示例2&#xff1a;4.示例3&#xff1a;5.提示&#xff1a;二、解题思路1.思路2.复杂度分析&#xff1a;3.算法图解三、代码实现总结一、编程题&#xff1…

网页防篡改实验(6)

实验简介 实验所属系列&#xff1a;网络攻防工具 实验对象&#xff1a; 本科/专科信息安全专业 相关课程及专业&#xff1a;信息网络安全概论、计算机网络 实验时数&#xff08;学分&#xff09;&#xff1a;2学时 实验类别&#xff1a;实践实验类 实验目的 1、了解网页防篡改…

7.数据库设计

学习过程参考&#xff08;后续章节同&#xff09; 【公开课】数据库系统概论&#xff08;王珊老师&#xff09;&#xff08;完结&#xff09; 《数据库系统概论》思维导图 第7章 数据库设计 | 数据库知识点整理 梳理 名词解释 数据库设计(database design)&#xff1a;数据库…

从2023年31省级政府工作报告看数据安全赛道 | 附下载

数字经济是支撑我国经济增长的新动能。据中国信息通信研究院数据&#xff0c;2021年我国数字经济规模超45万亿元、在GDP已占比40%&#xff0c;到2025年我国数字经济规模预计超60万亿元。春节前夕&#xff0c;地方两会陆续召开&#xff0c;从各地发布的2022年经济社会发展成绩来…

NodeJS与npm版本不一致时降级npm的方法

首先查看 Node.js 与 npm 版本对应关系&#xff1a;Node.js与npm版本查看。 安装 cnpm&#xff1a; npm install -g cnpm 查看一下 npm 和 cnpm 的镜像&#xff1a; npm config get registry cnpm config get registry 2 如果不是 https://registry.npm.taobao.org/ 的话就修…

【C++】CC++内存管理

就是你被爱情困住了&#xff1f;Wake up bro&#xff01; 文章目录一、C/C内存分布二、C语言中动态内存管理方式三、C中内存管理方式1.new和delete操作内置类型2.new和delete操作自定义类型&#xff08;仅限vs的底层实现机制&#xff0c;new和delete一定要匹配使用&#xff0c;…

【Linux】TCP网络编程流程

TCP网络编程流程 上一节博文我们提到了网络编程的基本流程 现在我们来了解TCP网络编程的流程 在这之前我们先要了解TCP 首先TCP是一种传输控制协议 在因特网协议族&#xff08;Internet protocol suite&#xff09;中&#xff0c;TCP层是位于IP层之上&#xff0c;应用层之…

MIT 6.S965 韩松课程 02

Lecture 02: Basics of Neural Networks TitleBasics of Neural NetworksLecturerSong HanDate09/13/2022Note AuthorGuangxuan Xiao (xgx)DescriptionReview the basics of deep learning and introduce efficiency metrics for neural networks. 回顾深度学习的基础知识&…

SparkSQL 核心编程

文章目录SparkSQL 核心编程1、新的起点2、SQL 语法1) 读取 json 文件创建 DataFrame2) 对 DataFrame 创建一个临时表3) 通过SQL语句实现查询全表3、DSL 语法1) 创建一个DataFrame2) 查看DataFrame的Schema信息3) 只查看"username"列数据4) 查看"username"列…

Elasticsearch(九)搜索---搜索辅助功能(下)--搜索性能分析

一、前言 上篇文章我们学习了ES的搜索辅助功能的一部分–分别是指定搜索返回的字段&#xff0c;搜索结果计数&#xff0c;分页&#xff0c;那么本次我们来学习一下ES的性能分析相关功能。 二、ES性能分析 在使用ES的过程中&#xff0c;有的搜索请求的响应比较慢&#xff0c;…

ChatGPT的火爆出圈,你对它有几分了解?

文章目录1.ChatGPT是什么&#xff1f;2.ChatGPT能做什么&#xff1f;2-1.什么是自然语言模型&#xff1f;3.ChatGPT带来的评价4.了解完ChatGPT之后&#xff0c;你会有什么反思&#xff1f;4-1.为什么微软不自己研发ChatGPT&#xff1f;4-2.Elon Musk为什么退出OpenAI公司&#…

分享116个JS焦点图代码,总有一款适合您

分享116个JS焦点图代码&#xff0c;总有一款适合您 116个JS焦点图代码下载链接&#xff1a;https://pan.baidu.com/s/1BKblAjuE98y5HlLAXZIndQ?pwdphgw 提取码&#xff1a;phgw Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj import os impo…

全国青少年编程等级考试scratch二级真题2022年9月(含题库答题软件账号)

青少年编程等级考试scratch真题答题考试系统请点击电子学会-全国青少年编程等级考试真题Scratch一级&#xff08;2019年3月&#xff09;在线答题_程序猿下山的博客-CSDN博客_小航答题助手1.数列&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;6&#xff0c;…

NLP学习笔记(八) GPT简明介绍

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲 GPT\text{GPT}GPT (Generative Pre-Training\textbf{G}\text{enerative}\ \textbf{P}\text{re-}\textbf{T}\text{raining}Generative Pre-Training) 实际上&#xff0c;GPT\text{GPT}GPT 包括一系列论文&#xff0c;具体有…

探针台常见的故障及解决方法

症状、 可能原因、 解决方法 移动样品后画面变模糊 —显微镜不垂直&#xff0c;调垂直显微镜 样品台不水平 —调水平样品台 显微镜视场亮度不足&#xff0c;边缘切割或看不到像—转换器不在定位位置上 把转换器转到定位位置上 管镜转盘不在定位位置上 —把管镜转盘转到定…

SpringCloud 中 Config、Bus、Stream、Sleuth

文章目录&#x1f68f; 第十三章 分布式配置中心&#x1f6ac; 一、Config 概述&#x1f6ac; 二、Config 快速入门&#x1f6ad; config-server&#xff1a;&#x1f6f9; 1、使用gitee创建远程仓库&#xff0c;上传配置文件&#x1f6f9; 2、导入 config-server 依赖&#x1…

【概念辨析】整型提升的深入理解(手画图解)

整型提升是一个小的知识点&#xff0c;但是请继续学习&#xff0c;保持空杯心态&#xff01; 目录 文章目录 前言 一、整型提升是什么&#xff1f; 二、发生整型提升的情况 1.字节数比int少的内置类型进行的整型提升 2.整型提升的规则 图解&#xff1a; 总结 前言 整型提升也是…

ubuntu18.04下交叉编译 nginx源码(支持推送H265的rtmp和http-flv)

ubuntu18.04下交叉编译 nginx源码&#xff08;支持推送H265的rtmp和http-flv&#xff09;适合在aarch64-linux-gnu平台下的交叉编译一、源码下载准备二、执行configure三、解决执行configure时遇到的出错问题1、checking for C compiler ... found but is not working2、error:…