【用unity实现100个游戏之15】开发一个类保卫萝卜的Unity2D塔防游戏3(附项目源码)

文章目录

  • 先看本次实现的最终效果
  • 前言
  • 绘制炮塔UI
  • 炮塔转向敌人
  • 生成炮弹
  • 旋转我们的子弹
  • 对敌人造成伤害,回收子弹
  • 自动发射子弹
  • 添加攻击间隔
  • 显示伤害字体
  • 设计通用泛型单例
  • 创建更多炮塔
  • 升级增加伤害
  • 升级缩短攻击间隔
  • 添加货币
  • 杀死敌人获取金币
  • 源码
  • 完结

先看本次实现的最终效果

在这里插入图片描述

前言

本期紧接着上一篇,主要内容主要是实现不同炮塔、攻击行为逻辑和伤害飘字效果。

绘制炮塔UI

在这里插入图片描述

新增炮塔脚本,配置炮塔攻击范围

[RequireComponent(typeof(CircleCollider2D))]
public class Turret : MonoBehaviour
{
    [SerializeField] private float attackRange = 3f; // 视为攻击范围
    private bool _gameStarted; // 游戏是否已经开始

    private void Start()
    {
        _gameStarted = true; // 设置游戏为已开始状态
    }

    private void OnDrawGizmos()
    {
        if (!_gameStarted)
        {
            // 在Scene视图中绘制攻击范围的可视化表示
            GetComponent<CircleCollider2D>().radius = attackRange; // 设置CircleCollider2D的半径为攻击范围
            Gizmos.DrawWireSphere(transform.position, attackRange); // 在指定位置绘制表示攻击范围的线框球体
        }
    }
}

在这里插入图片描述

炮塔转向敌人

修改Turret

public class Turret : MonoBehaviour
{
    //...

    public Enemy CurrentEnemyTarget { get; set; }
    private List<Enemy> _enemies;

    private void Start()
    {
        _gameStarted = true; // 设置游戏为已开始状态
        _enemies = new List<Enemy>();
    }

    private void Update()
    {
        GetCurrentEnemyTarget();
        RotateTowardsTarget();
    }

    //获取当前敌人目标
    private void GetCurrentEnemyTarget()
    {
        if (_enemies.Count <= 0)
        {
            CurrentEnemyTarget = null;
            return;
        }
        CurrentEnemyTarget = _enemies[0];
    }

    //面向敌人
    private void RotateTowardsTarget()
    {
        if (CurrentEnemyTarget == null) return;
        Vector3 targetPos = CurrentEnemyTarget.transform.position - transform.position;
        float angle = Vector3.SignedAngle(transform.up, targetPos, transform.forward);
        transform.Rotate(0f, 0f, angle);
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Enemy"))
        {
            Enemy newEnemy = other.GetComponent<Enemy>();
            _enemies.Add(newEnemy);
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Enemy"))
        {
            Enemy enemy = other.GetComponent<Enemy>();
            if (_enemies.Contains(enemy))
            {
                _enemies.Remove(enemy);
            }
        };
    }

	//...
}

记得修改敌人标签,添加刚体和碰撞体
在这里插入图片描述

效果,进入范围获取了目标,敌人超出范围,不再跟随
在这里插入图片描述

生成炮弹

新增Projectile,子弹控制脚本

public class Projectile : MonoBehaviour
{
    [SerializeField, Header("子弹移动速度")] 
    private float moveSpeed = 10f;
    
    private Enemy _enemyTarget; // 目标敌人

    private void Update()
    {
        if (_enemyTarget != null)
        {
            MoveProjectile();
        }
    }

    private void MoveProjectile()
    {
        // 将子弹向目标位置移动
        transform.position = Vector2.MoveTowards(transform.position,
            _enemyTarget.transform.position,
            moveSpeed * Time.deltaTime);
    }

    public void SetEnemy(Enemy enemy)
    {
        // 设置目标敌人
        _enemyTarget = enemy;
    }
}

制作子弹预制体,并挂载Projectile 脚本
在这里插入图片描述
新增TurretProjectile,控制子弹生成脚本

public class TurretProjectile : MonoBehaviour
{
    [SerializeField] private Transform projectileSpawnPosition; // 发射子弹的位置
    private ObjectPooler pooler; // 对象池管理器
    private Turret _turret;// 炮塔组件
    private Projectile _currentProjectileLoaded;// 当前装载的子弹

    private void Start()
    {
        pooler = GetComponent<ObjectPooler>(); // 获取对象池管理器组件
        _turret = GetComponent<Turret>();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.G))
        {
            LoadProjectile(); // 测试按下G键时加载子弹
        }

         // 如果有敌人目标、已加载子弹且敌人目标的健康值大于0
        if (_turret.CurrentEnemyTarget != null && _currentProjectileLoaded != null && _turret.CurrentEnemyTarget._enemyHealth.CurrentHealth > 0f)
        {
            // 解除子弹的父节点关系
            _currentProjectileLoaded.transform.parent = null;
            // 设置子弹的目标敌人
            _currentProjectileLoaded.SetEnemy(_turret.CurrentEnemyTarget);
        }
    }

    private void LoadProjectile()
    {
        GameObject newInstance = pooler.GetInstanceFromPool(); // 从对象池获取一个新的子弹实例
        newInstance.transform.localPosition = projectileSpawnPosition.position; // 设置子弹的位置为发射位置
        newInstance.transform.SetParent(projectileSpawnPosition); // 设置子弹的父节点为发射位置
        _currentProjectileLoaded = newInstance.GetComponent<Projectile>();// 获取子弹组件
        newInstance.SetActive(true); // 激活子弹
    }
}

挂载脚本,并配置参数
在这里插入图片描述
效果
在这里插入图片描述

旋转我们的子弹

修改Projectile

private void Update()
{
    if (_enemyTarget != null)
    {
        MoveProjectile();
        RotateProjectile();
    }
}

//控制子弹自动旋转
private void RotateProjectile()
{
    Vector3 enemyPos = _enemyTarget.transform.position - transform.position; // 计算目标敌人相对于子弹的位置向量
    float angle = Vector3.SignedAngle(transform.up, enemyPos, transform.forward); // 计算旋转角度

    transform.Rotate(0f, 0f, angle); // 绕Z轴旋转子弹
}

效果
在这里插入图片描述

对敌人造成伤害,回收子弹

修改Projectile

[SerializeField, Header("子弹造成的伤害值")] 
private float damage = 2f;
[SerializeField, Header("造成伤害的距离")] 
private float minDistanceToDealDamage = 0.1f;

private void MoveProjectile()
{
    // 将子弹向目标位置移动
    //...
    
    // 计算子弹与目标的距离
    float distanceToTarget = (_enemyTarget.transform.position - transform.position).magnitude;
    
    // 如果子弹与目标的距离小于最小距离,造成伤害并回收子弹
    if (distanceToTarget < minDistanceToDealDamage)
    {
        _enemyTarget._enemyHealth.DealDamage(damage);
        ObjectPooler.ReturnToPool(gameObject);
    }
}

效果
在这里插入图片描述

自动发射子弹

修改Projectile

public TurretProjectile Turretowner { get; set; }

private void MoveProjectile()
{
    // ...
    
    // 如果子弹与目标的距离小于最小距离,造成伤害并回收子弹
    if (distanceToTarget < minDistanceToDealDamage)
    {
        Turretowner.ResetTurretProjectile(); //重置装载的子弹
        //...
    }
}

修改TurretProjectile

private void Update()
{
    if(IsTurretEmpty() && _turret.CurrentEnemyTarget != null){
        LoadProjectile();
    }
	//...
}
//加载子弹
private void LoadProjectile()
{
    //...
    _currentProjectileLoaded.Turretowner = this;
}
    
//判断是否没有装载子弹
private bool IsTurretEmpty()
{
    return _currentProjectileLoaded == null;
}

//重置装载的子弹
public void ResetTurretProjectile()
{
    _currentProjectileLoaded = null;
}

在这里插入图片描述

添加攻击间隔

修改TurretProjectile

[SerializeField, Header("攻击间隔")] 
private float delayBtwAttacks = 2f;//攻击间隔

private float nextAttackTime;//下一次攻击时间

private void Update()
{
    if (Time.time > nextAttackTime)
    {
        // 如果有敌人目标、已加载子弹且敌人目标的健康值大于0
        if (_turret.CurrentEnemyTarget != null && _turret.CurrentEnemyTarget._enemyHealth.CurrentHealth > 0f)
        {
        	LoadProjectile();
        	
            // 解除子弹的父节点关系
            _currentProjectileLoaded.transform.parent = null;
            // 设置子弹的目标敌人
            _currentProjectileLoaded.SetEnemy(_turret.CurrentEnemyTarget);
        }
        nextAttackTime = Time.time + delayBtwAttacks;
    }

	//加载子弹
    private void LoadProjectile()
    {
        //。。。
        _currentProjectileLoaded.ResetProjectile();//重置炮弹
    }
}

修改Projectile

//重置炮弹
public void ResetProjectile()
{
    _enemyTarget = null;
    transform.localRotation = Quaternion.identity;
}

效果,每两秒发动一次攻击
在这里插入图片描述

显示伤害字体

绘制字体UI
在这里插入图片描述

配置动画,这个动画就大家自由发挥吧,怎么放大缩小或者上飘
在这里插入图片描述

新增脚本DamageText

public class DamageText : MonoBehaviour
{
    public TextMeshPro DmgText => GetComponent<TextMeshPro>();
    
    // 回收飘字
    public void ReturnTextToPool(){
        transform.SetParent(null);
        ObjectPooler.ReturnToPool(gameObject);
    }
}

挂载脚本到字体,动画完成时添加事件
在这里插入图片描述

新增DamageTextManager

public class DamageTextManager : MonoBehaviour
{
    public ObjectPooler Pooler { get; set; }

    public DamageText damageText;//飘字特效预制体
    public static DamageTextManager Instance;

    void Awake()
    {
        Instance = this;
    }


    private void Start()
    {
        Pooler = GetComponent<ObjectPooler>();
    }
}

挂载脚本,配置参数
在这里插入图片描述

修改Projectile,添加敌人受伤委托

public static Action<Enemy, float> OnEnemyHit;//敌人受伤委托

private void MoveProjectile()
{
    // 。。。
    
    // 如果子弹与目标的距离小于最小距离,造成伤害并回收子弹
    if (distanceToTarget < minDistanceToDealDamage)
    {
        OnEnemyHit?.Invoke(_enemyTarget, damage);
        
		//。。。
    }
}

新增EnemyFX

public class EnemyFX : MonoBehaviour
{
    [SerializeField] private Transform textDamageSpawnPosition; // 伤害数字显示位置

    private Enemy _enemy; // 敌人对象

    private void Awake()
    {
        _enemy = GetComponent<Enemy>(); // 获取敌人组件
    }

    // 敌人受到攻击时的处理方法
    private void EnemyHit(Enemy enemy, float damage)
    {
        if (_enemy == enemy) // 判断是否为当前敌人
        {
            GameObject newInstance = DamageTextManager.Instance.Pooler.GetInstanceFromPool(); // 从对象池中获取伤害数字的实例
            TextMeshPro damageText = newInstance.GetComponent<DamageText>().DmgText; // 获取伤害数字的Text组件
            damageText.text = damage.ToString(); // 设置显示的伤害数值
            newInstance.transform.SetParent(textDamageSpawnPosition); // 设置父物体为伤害数字显示位置
            newInstance.transform.position = textDamageSpawnPosition.position; // 设置显示位置
            newInstance.SetActive(true); // 激活显示
        }
    }

    private void OnEnable()
    {
        Projectile.OnEnemyHit += EnemyHit; // 注册敌人被攻击事件的监听
    }

    private void OnDisable()
    {
        Projectile.OnEnemyHit -= EnemyHit; // 取消注册敌人被攻击事件的监听
    }
}

挂载脚本
在这里插入图片描述
效果
在这里插入图片描述

设计通用泛型单例

新增泛型单例

using UnityEngine;

//简单的泛型单例
public class Singleton<T> : MonoBehaviour where T : Component
{
    private static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<T>();
                if (instance == null)
                {
                    GameObject newInstance = new GameObject();
                    instance = newInstance.AddComponent<T>();
                }
            }
            return instance;
        }
    }

    public void Awake()
    {
        instance = this as T;
    }
}

修改DamageTextManager ,简化代码

public class DamageTextManager : Singleton<DamageTextManager>
{
    public ObjectPooler Pooler { get; set; }

    public DamageText damageText;//飘字特效预制体

    private void Start()
    {
        Pooler = GetComponent<ObjectPooler>();
    }
}

创建更多炮塔

在这里插入图片描述
效果
在这里插入图片描述

升级增加伤害

修改TurretProjectile

[SerializeField, Header("造成的伤害值")]
protected float damage = 2f;
public float Damge { get; set; }

private void Start()
{
    //。。。
    Damge = damage;
}

//加载子弹
protected virtual void LoadProjectile()
{
    //。。。
    
    _currentProjectileLoaded.damage = Damge;
}

新增TurretUpgrade

public class TurretUpgrade : MonoBehaviour
{
    [SerializeField]
    private int upgradeInitialCost; // 升级初始费用
    [SerializeField]
    private int upgradeCostIncremental; // 升级费用递增值
    [SerializeField]
    private float damageIncremental; // 伤害递增值

    private TurretProjectile _turretProjectile;

    private void Start()
    {
        _turretProjectile = GetComponent<TurretProjectile>(); // 获取 TurretProjectile 组件
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.D))
        {
            UpgradeTurret(); // 测试升级炮塔
        }
    }

    private void UpgradeTurret()
    {
        _turretProjectile.Damge += damageIncremental; // 增加炮塔的伤害值
    }
}

配置参数测试
在这里插入图片描述

效果,按一次D,伤害增加2
在这里插入图片描述

升级缩短攻击间隔

修改TurretProjectile

public float DelayPerShot { get; set; }

DelayPerShot = delayBtwAttacks;

protected virtual void Update()
{
    if (Time.time > _nextAttackTime)
    {
        // 。。。
        
        _nextAttackTime = Time.time + DelayPerShot;
    }
}

修改TurretUpgrade

[SerializeField, Header("攻击间隔递减值")]
private float delayReduce;

private void UpgradeTurret()
{
    _turretProjectile.Damge += damageIncremental; // 增加炮塔的伤害值
    _turretProjectile.DelayPerShot -= delayReduce;// 减少炮塔的攻击间隔
}

测试配置
在这里插入图片描述
效果
在这里插入图片描述

添加货币

添加

public class CurrencySystem : Singleton<CurrencySystem>
{
    [SerializeField]
    private int coinTest; // 测试用的初始金币数量
    private string CURRENCY_SAVE_KEY = "MYGAME_CURRENCY";

    public int TotalCoins { get; set; } // 总金币数量

    private void Start()
    {
    	PlayerPrefs.DeleteKey(CURRENCY_SAVE_KEY);//开始清空金币数据
        LoadCoins(); // 加载金币数量
    }

    private void LoadCoins()
    {
        TotalCoins = PlayerPrefs.GetInt(CURRENCY_SAVE_KEY, coinTest); // 从 PlayerPrefs 中读取金币数量,默认为 coinTest 的值
    }

    public void AddCoins(int amount)
    {
        TotalCoins += amount; // 增加金币数量
        PlayerPrefs.SetInt(CURRENCY_SAVE_KEY, TotalCoins); // 将金币数量保存到 PlayerPrefs
        PlayerPrefs.Save(); // 保存 PlayerPrefs 的修改
    }

    public void RemoveCoins(int amount)
    {
        if (TotalCoins >= amount)
        {
            TotalCoins -= amount; // 减少金币数量
            PlayerPrefs.SetInt(CURRENCY_SAVE_KEY, TotalCoins); // 将金币数量保存到 PlayerPrefs
            PlayerPrefs.Save(); // 保存 PlayerPrefs 的修改
        }
    }
}

修改TurretUpgrade

public int UpgradeCost { get; set; }

private void Start()
{
    //。。。
    UpgradeCost = upgradeInitialCost;
}

private void UpgradeTurret()
{
    if (CurrencySystem.Instance.TotalCoins >= UpgradeCost)
    {
        _turretProjectile.Damge += damageIncremental; // 增加炮塔的伤害值
        _turretProjectile.DelayPerShot -= delayReduce;// 减少炮塔的攻击间隔
        UpdateUpgrade();
    }
}

private void UpdateUpgrade()
{
    CurrencySystem.Instance.RemoveCoins(UpgradeCost);//扣除金额
    UpgradeCost += upgradeCostIncremental;//加下次升级金额
}

配置,升级消耗10,每次升级消耗+20
在这里插入图片描述

效果,升级扣除了金额
在这里插入图片描述

杀死敌人获取金币

修改CurrencySystem,每杀一个敌人加一金币

private void AddCoins(Enemy enemy)
{
    AddCoins(1);
}

private void OnEnable()
{
    EnemyHealth.OnEnemyKilled += AddCoins;
}
private void OnDisable()
{
    EnemyHealth.OnEnemyKilled -= AddCoins;
}

效果,杀死敌人金额增加
在这里插入图片描述

源码

见本项目最后一节

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

epoll协程简述

协程的由来 【协程第二话】协程和IO多路复用更配哦~_哔哩哔哩_bilibili 协程类别:有栈(静态)协程, 无栈(动态协程) 协程epoll 当有需要等待的时候,就切换出去,要用汇编保存这个栈rsp 运行时,要根据协程上下文恢复出这个栈

Beego之Bee工具使用

1、bee工具使用 bee 工具是一个为了协助快速开发 Beego 项目而创建的项目&#xff0c;通过 bee 你可以很容易的进行 Beego 项目的创 建、热编译、开发、测试、和部署。Bee工具可以使用的命令&#xff1a; [rootzsx ~]# bee 2023/02/18 18:17:26.196 [D] init global config…

Java基础笔记

1.数据类型在java语言中包括两种: 第一种:基本数据类型 基本数据类型又可以划分为4大类8小种: 第一类:整数型 byte , short,int, long(没有小数的&#xff09; 第二类:浮点型 float,aouble(带有小数的&#xff09; 第三类:布尔型 boole…

【Rust】快速教程——模块mod与跨文件

前言 道尊&#xff1a;没有办法&#xff0c;你的法力已经消失&#xff0c;我的法力所剩无几&#xff0c;除非咱们重新修行&#xff0c;在这个世界里取得更多法力之后&#xff0c;或许有办法下降。——《拔魔》 \;\\\;\\\; 目录 前言跨文件mod多文件mod 跨文件mod //my_mod.rs…

高能分享:软件测试十大必问面试题(附带答案)

1 介绍之前负责的项目 参考答案&#xff1a;先大概描述一下这个项目是做什么的&#xff08;主要功能&#xff09;&#xff0c;包括哪些模块&#xff0c;是什么架构的&#xff08;B/S、C/S、移动端&#xff1f;&#xff09;&#xff0c;你在其中负责哪些模块的测试。期间经历了几…

Java后端工程师有福啦,CSDN里找到宝藏

目录 一、说明 二、操作步骤 一、说明 CDSN也有系统的java学习资料&#xff0c;有事无事翻翻挺好。 二、操作步骤 1、在CSDN首页顶端左边&#xff0c;点【学习】 2、在【学习】的页面&#xff0c;往下滑&#xff0c;找到【职业路线】 3、java后端工程师【入门版】【进阶版】…

Python基础:输入输出详解-输出字符串格式化

Python中的输入和输出是编程中非常重要的方面。 1. 输入输出简单介绍 1.1 输入方式 Python中的输入可以通过input()函数从键盘键入&#xff0c;也可以通过命令行参数或读取文件的方式获得数据来源。 1&#xff09;input()示例 基本的input()函数&#xff0c;会将用户在终端&…

Unity中Shader纹理的环绕方式

文章目录 前言一、修改环绕方式前的设置准备二、在纹理的设置面板可以修改环绕方式三、在Shader中&#xff0c;实现纹理的环绕方式切换1、在属性面板定义一个和纹理面板一样的纹理环绕方式下拉框2、在Pass中&#xff0c;定义枚举对应的变体3、在片元着色器中&#xff0c;纹理采…

腾讯云服务器收费标准是多少?腾讯云服务器收费标准表

你是否曾被繁琐复杂的服务器租赁费用搞得头昏脑胀&#xff1f;看着一堆参数和计费方式却毫无头绪&#xff1f;别担心&#xff0c;这篇文章就来帮你解决这个问题&#xff01;我们今天就来揭秘一下腾讯云服务器的收费标准&#xff0c;让大家轻松明白地知道如何租用腾讯云服务器。…

2023.11.17-hive调优的常见方式

目录 0.设置hive参数 1.数据压缩 2.hive数据存储格式 3.fetch抓取策略 4.本地模式 5.join优化操作 6.SQL优化(列裁剪,分区裁剪,map端聚合,count(distinct),笛卡尔积) 6.1 列裁剪: 6.2 分区裁剪: 6.3 map端聚合(group by): 6.4 count(distinct): 6.5 笛卡尔积: 7…

Go 语言变量类型和声明详解

在Go中&#xff0c;有不同的变量类型&#xff0c;例如&#xff1a; int 存储整数&#xff08;整数&#xff09;&#xff0c;例如123或-123float32 存储浮点数字&#xff0c;带小数&#xff0c;例如19.99或-19.99string - 存储文本&#xff0c;例如“ Hello World”。字符串值用…

2024年山东省职业院校技能大赛中职组“网络安全”赛项竞赛试题-C

2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-C 一、竞赛时间 总计&#xff1a;360分钟 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A、B模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略设置 A-3 流量完整性保护 A-4 …

技术分享 | 如何写好测试用例?

对于软件测试工程师来说&#xff0c;设计测试用例和提交缺陷报告是最基本的职业技能。是非常重要的部分。一个好的测试用例能够指示测试人员如何对软件进行测试。在这篇文章中&#xff0c;我们将介绍测试用例设计常用的几种方法&#xff0c;以及如何编写高效的测试用例。 ## 一…

337. 打家劫舍 III

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为 root 。 除了 root 之外&#xff0c;每栋房子有且只有一个“父“房子与之相连。一番侦察之后&#xff0c;聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连…

学习指南:如何快速上手媒体生态一致体验开发

过去开发者们在使用多媒体能力时&#xff0c;往往会遇到这样的问题&#xff0c;比如&#xff1a;为什么我开发的相机不如系统相机的效果好&#xff1f;为什么我的应用和其他的音乐一起发声了&#xff0c;我要怎么处理&#xff1f;以及我应该怎么做才能在系统的播控中心里可以看…

talbay---贝叶斯网络分析工具产品介绍

一 简介 talbay是拥有独立知识产权的国产软件&#xff0c;主要功能是贝叶斯网络建模、决策网络建模、概率计算、决策支持、敏感性分析、网络模型验证、机器学习等。talbay以用户为中心&#xff0c;简单易用, 计算准确高效&#xff0c;分析全面多样&#xff0c;在应用成熟理论及…

2023年“华为杯”第二十届中国研究生数学建模成绩数据分析(末尾有吃席群)

目录 0引言1、数据大盘1.1 官方数据1.2 分赛题统计数据1.2.1 A-F 获奖数1.2.2 A-F 获奖率 2、分学校统计获奖情况&#xff08;数模之星没有统计&#xff09;3、 数模之星4、吃席群5、写在最后的话 0引言 2023年华为杯成绩于2023年9月22-26日顺利举行&#xff0c;来自国际和全国…

23111706[含文档+PPT+源码等]计算机毕业设计SSM框架网上书城全套微信支付电商购物

文章目录 **软件开发环境及开发工具&#xff1a;****项目功能介绍&#xff1a;****论文截图&#xff1a;****实现&#xff1a;****代码片段&#xff1a;** 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;776871563 软件开发环境及开发工具&#xff…

MyBatis解析全局配置文件

MyBatis解析全局配置文件 MyBaits基础应用&#xff1a; 文档&#xff1a;MyBatis 链接&#xff1a;http://note.youdao.com/noteshare?id5d41fd41d970f1af9185ea2ec0647b64 传统JDBC和Mybatis相比的弊病 传统JDBC ​ Connection conn null; PreparedStatement pstmt …

面向面试学习,全网最齐全的软件测试面试题(含答案)

做测试的&#xff0c;我整理的真的很用心了&#xff0c;能找的新鲜面经都找了。 一面 1. 自我介绍 2. 面向对象的三种特性 集成用到了哪些特性 多态的具体使用场景 设计模式中的多态体现&#xff08;手撕&#xff09; 封装&#xff1a;将属性私有化&#xff1b;封装的意义&a…