javaOOP实现跳高大挑战!手把手教你实现小游戏!

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
大数据开发治理平台 DataWorks,不限时长
简介: javaOOP实现跳高大挑战!手把手教你实现小游戏!

跳高大挑战

由于该游戏复杂度稍高,笔者建议先学习猜拳游戏的文章之后再来完成该游戏。

题目

image.png

设计

image.png
常规:游戏主类,规则类
角色player类->因为有多个角色,所以应该有playData数据类
裁判judge类
根据题目要求需要体力能力比数据类

玩家:
属性:当前体力值,跳跃体力消耗率,能力峰值
跳跃行为:(跳跃高度、累计跳跃高度,累计跳跃次数),发现这三个量都与跳跃高度有关系,然后又发现求出跳跃高度的关键是求出率,所以就需要一个根据当前体力值获取率的方法。

体力能力比数据类:
数据:体力边界,体力能力比值(题目给的)
需要确定下界,所以需要有isMatched()方法

裁判:
单次裁决:add()方法灌输数据
多次裁决:排序

规则类:
可以先定义好常量和常规的方法(getxxx...)
一些具体的方法根据上述的需求分析再来确定。

结果呈现

image.png
image.png
image.png

运动员数据类

public class PlayerData implements Comparable<PlayerData>{
   
   
    /**
     * 玩家的数组下标
     */
    private int playerIndex;
    /**
     * 玩家的跳跃数据
     */
    private int count;



    public PlayerData(int playerIndex, int count) {
   
   
        this.playerIndex = playerIndex;
        this.count = count;
    }

    public int getPlayerIndex() {
   
   
        return playerIndex;
    }

    public int getCount() {
   
   
        return count;
    }


    @Override
    public int compareTo(PlayerData pd) {
   
   
        return count-pd.getCount();
    }
}

1 .数据类的定义:通常指包含一些get,set方法,同时也可能会实现Serialzable,Comparable等接口来实现数据类的可序列化和可比较特性,通常并不包含特殊方法。
2 .何时定义一个数据类?
数据类可以将不同种类的多个数据封装成为一个实体对象 ,当需要被多个模块或者方法使用的时候则可以定义数据类。(将数据提取出来,并进行操作)

体力能力比数据类

/**
 * 数据类:体力和能力的比值
 */
public class StrengthAbilityRatio {
   
   
    /**
     * 封装(超出基本类型范畴)
     * 体力边界值
     */
    private int strengthBound;
    /**
     * 当前体力边界值条件下所能发挥的能力比值
     */
    private float ratio;

    public StrengthAbilityRatio(int strengthBound, float ratio) {
   
   
        this.strengthBound = strengthBound;
        this.ratio = ratio;
    }

    /**
     * 没有用set的原因是 不能修改 构造器已经赋值了
     * 提取体力值边界
     * @return int
     */
    public int getStrengthBound() {
   
   
        return strengthBound;
    }

    /**
     * 提取当前体力值对应的比值
     * @return float
     */
    public float getRatio() {
   
   
        return ratio;
    }
    public boolean isMatched(float strength){
   
   
        return strength >= strengthBound;
    }
}

该类是在普通数据类的基础上添加了isMatched()方法便于将当前体力值与体力边界值的界限进行匹配,isMatched()方法本身是配合规则类中的getRatiosByStrength()方法一起使用的,通过当前体力值得到体力界限,通过体力界限和ratios数组得到跳跃高度比率。

规则类

public class Rule {
   
   
    private Scanner input;
    private Random rand;
    private final String NAME_REGEX = "^[\u4e00-\u9fa5]{2,}$";
    private final String DIGIT_REGEX = "^[0-9]{1,}$";
    /**
     * 体力和能力比值
     */
    private StrengthAbilityRatio[] ratios;
    public Rule(){
   
   
        ratios = new StrengthAbilityRatio[5];
        ratios[0] = new StrengthAbilityRatio(9,1);
        ratios[1] = new StrengthAbilityRatio(8,0.85f);
        ratios[2] = new StrengthAbilityRatio(6,0.7f);
        ratios[3] = new StrengthAbilityRatio(5,0.55f);
        ratios[4] = new StrengthAbilityRatio(0,0.3f);
        rand = new Random();//避免重复创建随机的工具对象
        input = new Scanner(System.in);
    }


    public String getInputName(String title){
   
   
        String name = null;
        System.out.printf("请输入"+title+"昵称:");
        do{
   
   
            name = input.nextLine();
            if(name.matches(NAME_REGEX))
                break;
            System.out.println("昵称必须为两个汉字以上的形式!请重新输入:");
        }while(true);
        return name;
    }

    /**
     * 根据用户剩余的体力值,获取能够发挥的能力值
     * @param strength 剩余体力
     * @return 比值
     */

    private float getRatioByStrength(float strength){
   
   
        for(StrengthAbilityRatio sar : ratios){
   
   
            if (sar.isMatched(strength)) {
   
   
                return sar.getRatio();
            }
        }
        return 0;
    }

    /**
     * 获取指定范围内的随机小数值
     * @param min 区间下限
     * @param max 区间上限
     * @return float
     */
    public float randomBetween(int min,int max){
   
   
        return min+rand.nextInt((max-min)*100)/100.0f;
    }

    /**
     * 获取控制台输入一个指定范围的整数
     * @param title
     * @param min
     * @param max
     * @return
     */
    public int getInputInt(String title,int min,int max){
   
   
        int digit = 0;
        do{
   
   
            System.out.print("请输入"+title+":");
            String num = input.next();
            if(num.matches(DIGIT_REGEX)){
   
   
                digit = Integer.parseInt(num);
                if(digit >= min && digit <= max){
   
   
                    break;
                }
                System.out.println("数值必须位于"+min+"~"+max+"之间,请重新输入:");
            }
        }while(true);
        return digit;
    }

    /**计算跳跃力和体力的消耗(选择合并为一个方法的原因:每次跳跃都会产生跳跃力消耗 并【伴随着】体力消耗 【伴随】说明【关联性】)
     * 注意临界:{
     *     如果达到了目标高度,但剩余体力为负值,说明剩余体力不足以支撑一次跳跃。
     *     如果要考虑此问题,只能按实际剩余的体力实施跳跃,而实际跳跃高度也成对应的比例关系。【临界问题】
     * }
     * @param strengthLeft 剩余体力
     * @param jumpAbility 跳跃力峰值
     * @param costRatio 体力消耗率
     * @return float[0]:实际的跳跃力 float[1]:体力的消耗值
     */
    public float[] getJumpAbilityAndStrengthCost(float strengthLeft,float jumpAbility,float costRatio){
   
   
        // 此处:strengthLeft 就是剩余体力,当剩余体力为0时,跳的高度肯定为0,但还没有达到目标高度
        float realJumpAbility = getRatioByStrength(strengthLeft)*jumpAbility;
        float realStrengthCost = realJumpAbility*costRatio;
        //如果实际消耗 超过跳前剩余的体力(最后一次的临界情况)
        if(strengthLeft < realStrengthCost){
   
   
            realJumpAbility *= strengthLeft / realStrengthCost;//比例关系!!!!!!
            realStrengthCost = strengthLeft;//只能消耗这么多的体力
        }
        return new float[] {
   
   realJumpAbility,realStrengthCost};
    }
}

关键点:在猜拳游戏中,笔者已经对getxxx方法的基本形式做出了总结,此处新增了一个常用方法,获取一个在一定范围内的随机小数。

public float randBetween(int min,int max){
   
   
    return min + (rand.randInt(max))*100/100.0f;
}

玩家类

public class Player extends Rule{
   
   
    /**
     * 昵称
     */
    private String nickName;
    /**
     * 能力峰值
     */
    private float jumpAbility;
    /**
     * 体力消耗率
     */
    private float strengthCostRatio;
    /**
     * 当期体力
     */
    private float currentStrength;
    public Player(){
   
   
        nickName = getInputName("运动员");
        jumpAbility = randomBetween(1,3);
        strengthCostRatio = randomBetween(0,1);
        currentStrength = randomBetween(5,10);
    }

    /**
     * 获取运动员姓名
     * @return String
     */
    public String getNickName() {
   
   
        return nickName;
    }

    /**
     * 根据目标高度实施跳跃并获取实际跳跃的次数
     * @param targetHeight 未知的东西选择入参 targetHeight 对运动员来说是未知的 在方法中不能改变的值一定要设置为常量
     * @return int 达到目标高度的次数 0:表示淘汰
     *                              >0: 表示成功
     */
    public int jump(final int targetHeight){
   
   
        int count = 0;
        float accJump = 0;
        /*存储累计跳跃的高度
          累计跳跃的高度小于targetHeight 是循环条件
         */
        while(accJump < targetHeight && currentStrength > 0){
   
   
            float [] arr = getJumpAbilityAndStrengthCost(currentStrength,jumpAbility,strengthCostRatio);
            // arr[0]表示单次跳跃高度,arr[1]单次表示消耗体力
            accJump += arr[0];
            currentStrength -= arr[1];
            count++;
            System.out.println(nickName+"本次跳了"+ arr[0] +"米 累计跳跃高度 " + accJump + "米 用了"+ count +" 次 剩余体力 "+currentStrength);
        }
        return currentStrength <=0 ? 0 : count;
    }


}

裁判类

public class Judge extends Rule {
   
   
    private PlayerData[] pds;// 运动员数据
    private int size;// 下标
    private int targetHeight = getInputInt("目标高度",10,15);//目标高度 目标高度的范围通过测试大概得出比较合适(有一定概率能够达到)的目标高度的范围
    public Judge(int size){
   
   //运动员数量
        pds = new PlayerData[size];
        this.size = 0;
    }

    /**获取目标高度
     * @return int 目标高度
     */

    public int getTargetHeight() {
   
   
        return targetHeight;
    }

    /**
     * 添加完成比赛的运动员的数据(此处的数据表示玩家相关联的下标和跳跃次数 如何使其相关联?---构造一个类和对象数组)
     * @param playerIndex 玩家下标
     * @param count 玩家跳跃的次数
     */
    public void add(int playerIndex,int count){
   
   
        pds[size++] = new PlayerData(playerIndex, count);
    }

    /**
     * 归并排序法 对所有玩家数据中的跳跃数据进行降序排序
     * @param pds
     * @param begin
     * @param end
     * @return
     */

    private PlayerData[] mergeSort(int begin,int end,PlayerData[] pds){
   
   
        if(begin == end){
   
   
            return new PlayerData[]{
   
   pds[begin]};
        }
        int mid = begin + (end - begin)/2;
        final PlayerData[] leftPds = mergeSort(begin, mid, pds);
        final PlayerData[] rightPds= mergeSort(mid + 1, end, pds);
        int left = 0,right = 0,mix = 0;
        PlayerData[] mixPds = new PlayerData[end-begin+1];
        while(left<leftPds.length && right<rightPds.length){
   
   
            mixPds[mix++] = leftPds[left].compareTo(rightPds[right]) < 0?leftPds[left++] : rightPds[right++];
        }
        while(left<leftPds.length){
   
   
            mixPds[mix++] = leftPds[left++];
        }
        while(right<rightPds.length){
   
   
            mixPds[mix++] = rightPds[right++];
        }
        return mixPds;
    }
    public PlayerData[] mergeSort(){
   
   
        return mergeSort(0,size-1,pds);
    }
    /**
     * 这里用一个无参的重载来调用mergeSort的原因是 mergeSort的其中一个参数是pds数组(运动员数据)
     * 而在外部调用的时候 是无法拿到运动员数据的 所以选择通过一个无参构造使得在JumpGame中能够进行排序
     */

}

1 .裁判的裁决可以分为单次裁决(在单次游戏进程之后,通过add()方法灌输运动员数据),多次裁决(进行排序),这点和猜拳游戏相类似。
2 .信息的权限:目标高度只有裁判知道,玩家并不知道。

游戏主类

public class JumpGame extends Rule {
   
   
    /**
     * 玩家信息
     */
    private Player[] players;
    /**
     * 裁判信息
     */
    private Judge judge;

    public JumpGame(){
   
   
        final int playerNum = getInputInt("运动员数量",1,10);
        players = new Player[playerNum];
        for (int i = 0; i < playerNum; i++) {
   
   //利用遍历型循环的目的 是能够通过下标进行关联型地存储数据
            players[i] = new Player();
        }
        judge = new Judge(playerNum);
    }
    public void start() {
   
   
        System.out.println("跳跃比赛开始...");
        for (int i = 0; i < players.length; i++) {
   
   //遍历型循环 使下标能够存入PlayerData的数据类中
            Player player = players[i];
            System.out.println("-------" + player.getNickName() + " 开始跳跃-------");
            final int count = player.jump(judge.getTargetHeight());
            System.out.println("-------" + player.getNickName() + " 完成跳跃-------\n");
            judge.add(i, count);
        }
        System.out.println("------- 最终结果 -------");
        PlayerData[] pds = judge.mergeSort();
        int rank = 0,index = 0;
        final Player[] eliminatedPlayers = new Player[pds.length];
        for(PlayerData pd : pds){
   
   
            if(pd.getCount() > 0){
   
   
                rank++;
                Player player = players[pd.getPlayerIndex()];//通过玩家的下标 获取玩家的信息 从而才能输出结果的nickName等信息
                String rst = "跳跃"+pd.getCount()+"次";
                System.out.println("第"+rank+"名\t"+player.getNickName()+"\t"+rst);
            }else{
   
   
                eliminatedPlayers[index++] = players[pd.getPlayerIndex()];
            }
        }
        for(Player player:eliminatedPlayers){
   
   
            if(null != player){
   
   
                String rst = "淘汰";
                System.out.println("       \t"+player.getNickName() + "\t"+rst);
            }
        }
    }
}
目录
相关文章
|
3天前
|
人工智能 自然语言处理
Sora如何用?小白教程,一文带你看清
仅仅凭借文字就可以生成一段视频!近日,OpenAI的一款新产品又火出圈了。当地时间周四(2月15日),OpenAI发布了首个文生视频模型Sora。 2024年2月16日,OpenAI在官网上正式宣布推出**文本生成视频**的[大模型 Sora](https://openai.com/sora),该工具可以通过使用文本迅速制作出一段长达60秒的视频,视频中可以呈现多个角色、特定动作、以及复杂场景。OpenAI的官网上现已更新了48个视频案例,可以说是效果逼真,能展现艳丽的色彩,呈现准确的细节,连人物角色都是表情丰富。
|
3天前
|
IDE 开发工具
编程竞赛体验感受
编程竞赛体验感受
24 0
|
7月前
|
JavaScript Java
【游戏开发】自从遇见了口袋方舟后,我的世界变得精彩了起来
【游戏开发】自从遇见了口袋方舟后,我的世界变得精彩了起来
84 0
|
12月前
|
机器学习/深度学习 存储 自然语言处理
不讲废话普通人了解 ChatGPT——基础篇第一课
不知道大家在第一次会使用 ChatGPT 并尝试和他对话时有没有感到震惊。当ChatGPT首次推出时,我立即被它的功能所吸引。
173 0
|
开发工具
想学做游戏到底该怎么学
嗨!大家好,我是小蚂蚁。 遇到过很多想学习做游戏却又不得章法的人,有些人可能只是有个想法,有些人真的付诸了行动。但是大部分人最终都是以失败而告终的,不是说最终没有做出来一个游戏,而是连第一步的门槛也没迈的过去。 做游戏做了这么多年,也教了不少的学员,我觉得我至少有一定的经历,可以来说一下,想学习做游戏到底该怎么学。
164 0
|
弹性计算 Kubernetes 关系型数据库
初入阿里云,上手走一波
简述个人体验的阿里云产品及相关的操作内容,包括ECS、Mysql、DMS、OSS、Linux等
初入阿里云,上手走一波
|
数据可视化 Windows
推荐5款实用小工具,第五款更是小白最爱
作为一个黑科技软件爱好者,电脑里肯定是不会缺少这方面的东西,今天的5款实用小工具闪亮登场了。
170 0
推荐5款实用小工具,第五款更是小白最爱
|
移动开发 小程序 JavaScript
手撸一个在线学习在线教育小程序
最近有小伙伴找小孟开发了一个在线教育的小程序项目。
124 0
手撸一个在线学习在线教育小程序
|
关系型数据库 MySQL Java
手把手教你做一个安卓点餐系统
最近有小伙伴要学习安卓,今天给大家展示一个安卓系统的开发,希望能帮到你学习!
327 0
手把手教你做一个安卓点餐系统
|
存储 小程序 数据库
手把手教学,从零到一打造一款专属的情侣小程序
很久之前就想做个情侣小程序来记录我们之间的一些事情,偶然翻开一年前自己制作的一个小程序(未完成版),虽然代码下的有点乱,但感觉可以重构一下,在此给大家展示一下,也希望在设计和功能上,大家可以给点意见,后续有空再进行完善。
1096 0
手把手教学,从零到一打造一款专属的情侣小程序

热门文章

最新文章