Java小游戏

news2025/1/22 19:45:54

一、需求

             

 二、思路一

        HP当然是怪物的一个属性成员,而武器是角色的一个属性成员,类型可以使字符串,用于描述目前角色所装备的武器。角色类有一个攻击方法,以被攻击怪物为参数,当实施一次攻击时,攻击方法被调用,而这个方法首先判断当前角色装备了什么武器,然后据此对被攻击怪物的HP进行操作,以产生不同效果

package com.homework.game;

public class Monster {
    //定义怪物名称
    public String monster_name;
    //定义怪物血量
    public int monster_hp;
    //定义构造方法
//    public Monster(){
//    }
    //定义有参数的构造方法,主函数中调用此方法可以传递怪物的名称和初始血量
    public Monster(String name,int hp){
        //给怪物名称和初始血量赋值
        this.monster_name = name;
        this.monster_hp = hp;
    }
//    //设置怪物的名称
//    public void setMonsterName(String name){
//        this.monster_name = name;
//    }
    //返回怪物名称
    public String getMonsterName(){
        return this.monster_name;
    }
    //设置怪物的血量
    public void setMonsterHp(int hp){
        this.monster_hp = hp;
    }
//返回怪物血量
    public int getMonsterHp(){
        return this.monster_hp;
    }
}





package com.homework.game;

import javax.sound.midi.SoundbankResource;
import java.util.Random;

public class Player {
    //创建玩家名称变量
    public String player_name;
    //创建玩家武器变量
    public String player_weapon;
    //设置玩家名称方法
    public void setPlayerName(String name){
        this.player_name = name;
    }
    //获取玩家名称方法
    public String getPlayerName(){
        return this.player_name;
    }
    //设置玩家武器
    public void setPlayWeapon(String weapon){
        this.player_weapon = weapon;
    }
    //获取玩家武器
    public String getPlayerWeapon(){
        return this.player_weapon;
    }
    //玩家攻击方法
    public void attackMethod(Monster monster){
//        System.out.println(monster.getMonsterHp());
//        System.out.println(this.player_weapon);
        if (monster.getMonsterHp() > 0){
            if("木剑".equals(this.player_weapon)){
               int hp = monster.getMonsterHp();
               hp = hp - 20;
               monster.setMonsterHp(hp);
               if (hp > 0){
                   System.out.println(this.player_name+"用"+this.player_weapon+"打了20HP,"+
                           monster.getMonsterName()+"还剩余"+monster.getMonsterHp()+"血量,可继续攻击");
               }else {
                   System.out.println(monster.getMonsterName()+"被击杀!!!");
                   return;
               }
            }else if("铁剑".equals(this.player_weapon)){
                if (monster.getMonsterHp() > 0){
                    int hp = monster.getMonsterHp();
                    hp = hp - 50;
                    monster.setMonsterHp(hp);
                    if (hp > 0){
                        System.out.println(this.player_name+"用"+this.player_weapon+"打了50HP,"+
                                monster.getMonsterName()+"还剩余"+monster.getMonsterHp()+"血量,可继续攻击");
                    }else {
                        System.out.println(monster.getMonsterName()+"被击杀!!!");
                        return;
                    }
                }else {
                    System.out.println(monster.getMonsterName()+"死了,不需要攻击了!!!");
                    return;
                }
            }else if("魔剑".equals(this.player_weapon)){
                if (monster.getMonsterHp() > 0){
                    int random = ((int)(Math.random()*10))+1;
                    int less_hp = (random > 5)?200:100;
                    if (less_hp == 200){
                        System.out.println("暴击了!!!!");
                    }
                    int hp = monster.getMonsterHp();
                    hp = hp - less_hp;
                    monster.setMonsterHp(hp);
                    if (hp > 0){
                        System.out.println(this.player_name+"用"+this.player_weapon+"打了"+less_hp+"HP"+
                                monster.getMonsterName()+"还剩余"+monster.getMonsterHp()+"血量,可继续攻击");
                    }else {
                        System.out.println(monster.getMonsterName()+"被击杀!!!");
                        return;
                    }
                }
            }else {
                System.out.println("没有武器,无法攻击");
            }
        }else {
            System.out.println(monster.getMonsterName()+"死了,无需攻击!!!");
        }
    }
}




package com.homework.game;

import java.util.Scanner;

public class TestMain {
    public static void main(String[] args) {
        System.out.println("------------------游戏开始------------------");
        //创建怪物对象
        Monster monster = new Monster("魔王",500);
        //创建玩家对象
        Player player = new Player();
        //创建两个录入对象

        Scanner player_name_scanner = new Scanner(System.in);

        Scanner player_weapon_scanner = new Scanner(System.in);
        //定义玩家名称变量
        System.out.println("请输入玩家名称:");
        String player_name = player_name_scanner.next();
        while(true){
            if(monster.getMonsterHp() > 0){
                System.out.println("请输入武器准备(木剑、铁剑、魔剑):");
                String player_weapon = player_weapon_scanner.next();
                player.setPlayerName(player_name);
                player.setPlayWeapon(player_weapon);
                player.attackMethod(monster);
            }else {
                System.out.println("--------------------You Win----------------------");
                break;
            }
        }
    }
}

 小结:

计的角色类的攻击方法很长,并且方法中有一个冗长的if…else结构,且每个分支的代码的业务逻辑很相似,只是很少的地方不同。

再者,上述设计思路,违反了O【Open】C【Close】P原则。在这个设计中,如果以后我们增加一个新的武器,如倚天剑,每次攻击损失500HP,那么,我们就要打开角色类,修改攻击方法。而我们的代码应该是对修改关闭的,当有新武器加入的时候,应该使用扩展完成,避免修改已有代码。

一般来说,当一个方法里面出现冗长的if…else或switch…case结构,且每个分支代码业务相似时,往往预示这里应该引入多态性来解决问题。而这里,如果把不同武器攻击看成一个策略,那么引入策略模式(Strategy Pattern)是明智的选择

Tip:OCP原则,即开放关闭原则,指设计应该对扩展开放,对修改关闭。

Tip:策略模式,英文名Strategy Pattern,指定义算法族,分别封装起来,让他们之间可以相互替换,此模式使得算法的变化独立于客户。

三、思路二

        因上述原因,我们重新设计,得到以下思路

 

package com.homework.game2;
//定义一个攻击接口,以怪物作为参数,各类武器实现这个攻击接口
public interface Attack {
    public void attcak(Monsters monsters);
}


package com.homework.game2;
//武器----木剑
public class WoodenSword implements Attack {
    @Override
    public void attcak(Monsters monsters) {
       //通知怪物失去对应血量
        monsters.bloodLoss(20,"木剑");
    }
}



package com.homework.game2;
//武器----铁剑类
public class IronSword implements Attack{
    @Override
    public void attcak(Monsters monsters) {
        //通知怪物掉血50
        monsters.bloodLoss(50,"铁剑");
    }

}


package com.homework.game2;

import javax.sound.midi.SoundbankResource;

//武器-----魔剑类
public class MagicSword implements Attack{
    @Override
    public void attcak(Monsters monsters) {
        int random = ((int)(Math.random()*10))+1;
        if(random > 5){
            System.out.println("魔剑暴击了,击杀200Hp!!!");
            monsters.bloodLoss(200,"魔剑");
        }else {
            monsters.bloodLoss(100,"魔剑");
        }
    }
}


package com.homework.game2;
//怪物类
public class Monsters {
    //定义怪物的名称
    public String monsters_name;
    //定义怪物的血量
    public int monsters_hp;
//    //构造方法,用来创建对象
//    public Monsters(){}
//    //定义怪物的构造方法,在主方法中传入参数,初始化怪物属性
    public Monsters(String name,int hp){
        this.monsters_name = name;
        this.monsters_hp = hp;
    }
//    //获取怪物名称方法
//    public String getMonstersName(){
//        return this.monsters_name;
//    }
//    //设置怪物血量
//    public void setMonstersHp(int hp){
//        this.monsters_hp = hp;
//    }
//    //获取怪物血量
//    public int getMonsterHp(){
//        return this.monsters_hp;
//    }
    //怪物掉血的方法,参数  1.掉血量;2.使用的武器
    Players players =new Players("王也");
    public void bloodLoss(int hp,String weapon_name){
        if(this.monsters_hp > 0){
            this.monsters_hp = this.monsters_hp - hp;
            if(this.monsters_hp > 0){
                System.out.println(players.getPlayersName()+"用"+weapon_name+"攻击了"+this.monsters_name+hp+
                        "Hp,剩余"+this.monsters_hp+"Hp,可以继续攻击");
            }else {
                System.out.println(this.monsters_name+"死了,无需攻击");
            }
        }else {
            System.out.println(this.monsters_name+"死了,无需攻击");
            return;
        }
    }
}




package com.homework.game2;
//玩家类
public class Players {
    //定义玩家名称
    public String players_name;
    //定义玩家武器
    public Attack players_weapon;
    //设置玩家构造方法,初始化玩家名称
    public Players(String name){
        this.players_name = name;
    }
//    //设置玩家名称方法
//    public void setPlayersName(String name){
//        this.players_name = name;
//    }
    //获取玩家名称方法
    public String getPlayersName(){
        return this.players_name;
    }
    //接口回调 Attack weapon 接口回调变量
    //设置玩家武器方法,传入接口参数,将变量赋值给this.players_weapon
    public void setPlayersWeapon(Attack weapon){
        this.players_weapon = weapon;
    }
//    //获取玩家武器方法
//    public Attack getPlayersWeapon(){
//        return this.players_weapon;
//    }
    //玩家攻击方法
    public void player_AttcakMethod(Monsters monsters){
        this.players_weapon.attcak(monsters);
    }

}



package com.homework.game2;

public class TestMain {
    public static void main(String[] args) {
        //创建怪物对象
        Monsters monsters = new Monsters("大魔王",200);
        //创建玩家对象
        Players players = new Players("王也");
        players.setPlayersWeapon(new WoodenSword());
        players.player_AttcakMethod(monsters);
        players.setPlayersWeapon(new IronSword());
        players.player_AttcakMethod(monsters);
        players.setPlayersWeapon(new MagicSword());
        players.player_AttcakMethod(monsters);
    }
}

改进后的代码有如下优点:

第一,虽然类的数量增加了,但是每个类中方法的代码都非常短,没有了以前攻击方法那种很长的方法,也没有了冗长的if…else,代码结构变得很清晰。

第二,类的职责更明确了。在第一个设计中,角色不但负责攻击,还负责给怪物减少HP和判断怪物是否已死。这明显不应该是角色的职责,改进后的代码将这两个职责移入怪物内,使得职责明确,提高了类的内聚性。

第三,引入Strategy[策略]模式后,不但消除了重复性代码,更重要的是,使得设计符合了OCP。如果以后要加一个新武器,只要新建一个类,实现武器接口,当角色需要装备这个新武器时,客户代码只要实例化一个新武器类,并赋给角色的武器成员就可以了,已有的角色和怪物代码都不用改动。这样就实现了对扩展开发,对修改关闭

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

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

相关文章

2021年09月 C/C++(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:最佳路径 如下所示的由正整数数字构成的三角形: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的…

【力扣每日一题】2023.8.24 统计参与通信的服务器

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目顾名思义,要我们统计参与通信的服务器,给我们一个二维矩阵,元素为1的位置则表示是一台服务器。 …

特殊的矩阵与特殊的矩阵关系———实对称、正定、对角、零矩阵

一、特殊的矩阵 1、实对称矩阵 定义:都是实数,且 性质: (1)可以用特征值来求A的大小 (2)可以得到A的秩 (3)必定可以相似对角化 运用: 与实对称矩阵A合同的矩…

线性代数的学习和整理12: 矩阵与行列式,计算上的差别对比

目录 1 行列式和矩阵的比较 2 简单总结矩阵与行列式的不同 3 加减乘除的不同 3.1 加法不同 3.2 减法不同 3.3 标量乘法/数乘 3.3.1 标准的数乘对比 3.3.2 其他数乘对比 3.4 乘法 4 初等线性变换的不同 4.1 对矩阵进行线性变换 4.2 对行列式进行线性变换呢&#xf…

平衡二叉树的插入和删除(从现在开始摆脱旋转)

平衡二叉树是指任意节点的左子树和右子树高度之差的绝对值不超过1 一.插入操作 1.找到合适位置插入 2.从下到上,沿着插入节点与根节点的连线,找到不平衡的二叉树 以68为根节点的二叉树平衡,左右子树高度差为1 以60为根节点的二叉树不平衡&a…

【NX】NX中将点从一个坐标系映射到另一个坐标系

直接上代码吧,主要是使用了UF_CSYS_map_point函数: bool CAMToolPathToolkit::MapPointThroughRootWork(const AUTUMOONMathPoint3d &iPt, AUTUMOONMathPoint3d &oPt, int nTransMethod) {// 将点坐标转换为工作坐标系下坐标double arrPointInp…

有限与无限游戏 | 真北荐书

2023佛山敏捷之旅暨DevOps Meetup志愿者为进行大会的组织与准备,每周三晚有一个例会。 例会前等人的时间,涌现出一个小的分享环节。今天分享这本书:《有限与无限游戏》。 大家选择成为志愿者,是一个无限游戏。而组织活动和完成各种…

JavaSE 认识String类

目录 1 创建字符串2 字符串比较相等3 字符串常量池4 理解字符串不可变5 字符、字节与字符串5.1 字符与字符串5.2 字节与字符串5.3 小结 6 字符串常见操作6.1 字符串比较6.2 字符串查找6.3 字符串替换6.4 字符串拆分6.5 字符串截取6.6 其他操作方法 7 StringBuffer 和 StringBui…

AIGC ChatGPT 按年份进行动态选择的动态图表

动态可视化分析的好处与优势: 1. 提高信息理解性:可视化分析使得大量复杂的数据变得易于理解,通过图表、颜色、形状、尺寸等方式,能够直观地表现不同的数据关系和模式。 2. 加快决策速度:数据可视化可以帮助用户更快…

stm32 之20.HC-06蓝牙模块

原理图显示使用usart3串口使用的是PB10和PB11引脚 直接配置usart3串口协议 void usart3_init(uint32_t baud) {GPIO_InitTypeDef GPIO_InitStructureure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;//端口B硬件时钟打开RCC_AHB1PeriphClockC…

Qt中XML文件创建及解析

一 环境部署 QT的配置文件中添加xml选项&#xff1a; 二 写入xml文件 头文件&#xff1a;#include <QXmlStreamWriter> bool MyXML::writeToXMLFile() {QString currentTime QDateTime::currentDateTime().toString("yyyyMMddhhmmss");QString fileName &…

Codeforces Round 887 Div.3 A~D

文章目录 A. Blackboard ListB. Minimize Permutation SubarraysC. No Prime DifferencesD. Bracket Walk A. Blackboard List Problem - A - Codeforces 一个只有两个数的数组&#xff0c;选择数组中的任意两个数&#xff0c;计算它们差值的绝对值并加入数组 给定一个长度为…

计算机竞赛 基于人工智能的图像分类算法研究与实现 - 深度学习卷积神经网络图像分类

文章目录 0 简介1 常用的分类网络介绍1.1 CNN1.2 VGG1.3 GoogleNet 2 图像分类部分代码实现2.1 环境依赖2.2 需要导入的包2.3 参数设置(路径&#xff0c;图像尺寸&#xff0c;数据集分割比例)2.4 从preprocessedFolder读取图片并返回numpy格式(便于在神经网络中训练)2.5 数据预…

[JavaWeb]【十三】web后端开发-原理篇

目录 一、SpringBoot配置优先级 1.1 配置优先级比较 1.2 java系统属性和命令行参数 1.3 打包运行jar 1.4 综合优先级​编辑 二、Bean管理 2.1 获取bean 2.2 bean作用域 2.2.1 五种作用域 2.2.2 配置作用域 2.3 第三方bean 2.3.1 编写公共配置类 三、SpringBoot原理 …

二级MySQL(六)——表格数据插入

1、插入完整的数据记录&#xff1a; INSERT INTO tb_student VALUES(2014210103,王玲,女,1998-02-21,安徽,汉,CS1401); 结果&#xff1a; 2、插入指定位置的数据&#xff1a; 直接输入是错的&#xff1a; 需要指出插入的列名称&#xff1a; 结果&#xff1a; 中间两列允许输入…

cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容。应以 ‘{layoutlib}‘ 等等开头

不与世俗为伍。哪怕这是自己许给自己的诅咒。 —— 宫崎骏 《红猪》 最近&#xff0c;在使用最新版的AndroidStudio打开一个两年前的项目时候&#xff0c;报了一个如下的错误&#xff1a;【cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容】。应以 ‘…

基于PyTorch框架下网络模型的使用与修改

目录 1 损失函数和反向传播1.1 损失函数1.2 反向传播 2 优化器3 现有网络模型的使用及修改4 网络模型的保存与读取4.1 网络模型的保存4.2 网络模型的读取&#xff08;加载&#xff09; 5 完整的模型训练套路6 利用GPU训练模型7 完整的模型验证套路&#xff1a; 1 损失函数和反向…

基于DolphinScheduler的调度流程梳理及落地实践

目 录 01 背景‍ 02 主流调度引擎 ‍‍‍‍‍‍‍ 03 DolphinScheduler核心概念及调度过程‍‍‍‍‍‍ 04 开发实践 01‍ 背景‍‍ 随着数据中台概念及相关技术逐渐成熟、落地&#xff0c;不断有企业将其应用到自身业务中&#xff0c;将原本分散的各系统数据进行整合、分析…

【FAQ】安防监控视频汇聚平台EasyCVR接入GB国标设备,无法显示通道信息的排查方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

http协议与apache

http概念&#xff1a; 互联网&#xff1a;是网络的网络&#xff0c;是所有类型网络的母集 因特网&#xff1a;世界上最大的互联网网络。即因特网概念从属于互联网概念 万维网&#xff1a;万维网并非某种特殊的计算机网络&#xff0c;是一个大规模的、联机式的信息贮藏库&…