Java小游戏

一、需求

             

 二、思路一

        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。如果以后要加一个新武器,只要新建一个类,实现武器接口,当角色需要装备这个新武器时,客户代码只要实例化一个新武器类,并赋给角色的武器成员就可以了,已有的角色和怪物代码都不用改动。这样就实现了对扩展开发,对修改关闭

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

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

相关文章

C++设计模式之适配器模式

一、适配器模式 适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成另一个类所期望的接口,以便两个类能够协同工作。 适配器模式可以解决现有类接口与所需接口不匹配的问题,使得原本因接口不…

BlazorServer中C#与JavaScript的相互调用

BlazorServer中C#与JavaScript的相互调用 前言: ​ 虽然BlazorServer中推荐使用C#在razor页面中的替代JavaScript来完成逻辑的编写,但当需要使用第三方的javascript文件/组件里的内容时,则难免要在C#中调用其方法或对象。反之当你的(用到第…

湖北咸宁农业三维扫描数字化农业3d打印制造应用-CASAIM中科广电

农业是人类衣食之源、生存之本,是一切生产的首要条件,CASAIM在农业三维扫描和3d打印应用上有丰富经验。 1.三维扫描技术在农业领域的应用 CASAIM三维扫描是集光学、机电和计算机技术于一体的高新无损检测技术,能够对实物的空间外形、结构乃…

Redis数据结构全解析【万字详解】

文章目录 前言一、SDS1、SDS的必要性2、SDS的数据结构3、SDS的优势O(1)复杂度获取字符串长度二进制安全不会发生缓冲区溢出节省空间 二、链表1、结构设计2、优缺点 三、压缩列表1、结构设计2、连续更新3、压缩列表的缺陷 四、哈希表1、结构设计2、哈希冲…

ubuntu安装goland

下载并解压goland sudo tar -C /opt/ -xzvf goland-2023.1.3.tar.gz配置应用图标 新建文件: vim /usr/share/applications/goland.desktop文件中写入如下内容: [Desktop Entry] TypeApplication NameGoLand Icon/opt/GoLand/bin/goland.png Exec/op…

科技赋能,教育革新——大步迈向体育强国梦

在 "全民健身"、"体育强国建设"战略的推进下,体育考试成绩被纳入重要升学考试且分值不断提高,体育科目的地位逐步上升到前所未有的高度,在此趋势下,体育教学正演变出更多元化、个性化的需求。然而现实中却面临…

centos7安装MySQL8

Centos7安装MySQL8 MySQL版本:8.0.34 1.安装前准备 (1)查看是否安装mariadb [rootkb135 ~]# rpm -qa|grep mariadb (2)卸载mariadb并检查是否卸干净 [rootkb135 ~]# rpm -e --nodeps mariadb-libs-5.5.68-1.el7.x8…

【C语言】2023.8.27C语言入学考试复盘总结

前言 本篇文章记录的是对于2023年8月27日的 C语言 的入学考试的整理总结 成绩:220/240 题目:9/12 错题整理 首先先对于我没做出来的三道题做一个整理 错题1:7-4 分段函数PLUS 题干 以下是一个二元分段函数,请你根据所给的函…

SketchBook软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 SketchBook是一款由Autodesk公司开发的绘画和绘图软件,它适用于各种操作系统和平台,如Windows、macOS、iOS和Android等。 SketchBook是一款专业的绘图软件,旨在满足各种绘画和绘图需求。它提…

TensorBoard的使用

TensorBoard:对图像进行变换 1. SummaryWriter的使用 ctrl类出现注释解析: 将条目直接log_dir写入要成为由TensorBoard使用。 “摘要编写器”类提供了一个高级 API 来创建事件文件,并在给定目录中添加摘要和事件。该类更新文件内容异步。…

如何配置一个永久固定的公网TCP地址来SSH远程树莓派?

文章目录 如何配置一个永久固定的公网TCP地址来SSH远程树莓派?前置条件命令行使用举例:修改cpolar配置文件 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 …

【Apollo学习笔记】——规划模块TASK之PATH_REUSE_DECIDER

文章目录 前言PATH_REUSE_DECIDER功能简介PATH_REUSE_DECIDER相关配置PATH_REUSE_DECIDER总体流程PATH_REUSE_DECIDER相关子函数IsCollisionFreeTrimHistoryPathIsIgnoredBlockingObstacle和GetBlockingObstacleS Else参考 前言 在Apollo星火计划学习笔记——Apollo路径规划算…

【CSS】CSS 特性 ( CSS 优先级 | 优先级引入 | 选择器基本权重 )

一、CSS 优先级 1、优先级引入 定义 CSS 样式时 , 可能出现 多个 类型相同的 规则 定义在 同一个元素上 , 如果 CSS 选择器 相同 , 执行 CSS 层叠性 , 根据 就近原则 选择执行的样式 , 如 : 出现两个 div 标签选择器 , 都设置 color 文本颜色 ; <style>div {color: re…

Cookie for Mac:隐私保护工具保护您的在线隐私

随着互联网的发展&#xff0c;我们每天都会浏览各种网站&#xff0c;享受在线购物、社交娱乐和学习资料等各种便利。然而&#xff0c;您是否曾经遇到过需要频繁输入用户名和密码的情况&#xff1f;或者不方便访问您常用的网站&#xff1f;如果是这样&#xff0c;那么Cookie for…

【手写promise——基本功能、链式调用、promise.all、promise.race】

文章目录 前言一、前置知识二、实现基本功能二、实现链式调用三、实现Promise.all四、实现Promise.race总结 前言 关于动机&#xff0c;无论是在工作还是面试中&#xff0c;都会遇到Promise的相关使用和原理&#xff0c;手写Promise也有助于学习设计模式以及代码设计。 本文主…

【五】sql 语言 -- 概览

SQL 语言概述SQL 语言提出和发展SQL 语言的功能概述利用 SQL 语言建立数据库学生选课数据库 SCT1. 定义数据库和表 SQL-DDL创建数据库的语句—Create Database创建关系/表的语句—Create Table 2. 向表中追加元组 SQL-DML 利用 SQL 语言进行简单查询单表查询 - SELECT-FROM-WHE…

MySQL安装记录

背景 Windows系统重装了, 想恢复一下之前的MySQL环境, 而且本地数据库也是比较常用的, 刚好本次也在安装, 做一个简单的记录. 也算是自己的学习记录输出. 遇到的问题当然也可以同时记录在这里, 方便后 续回顾. 资料包 百度网盘 // TODO 估计放了也会被CSDN屏蔽, 这里就不放…

Redis 的混合持久化

RDB 相比于 AOF&#xff0c;数据恢复的速度更快&#xff0c;因为是二进制数据&#xff0c;直接加载进内存即可&#xff0c;但是 RDB 的频率不好把握。 如果频率太低&#xff0c;在两次快照期间服务器发生宕机&#xff0c;可能会丢失较多的数据如果频率太高&#xff0c;频繁写入…

软件工程(十三) 设计模式之结构型设计模式(一)

前面我们记录了创建型设计模式,知道了通过各种模式去创建和管理我们的对象。但是除了对象的创建,我们还有一些结构型的模式。 1、适配器模式(Adapter) 简要说明 将一个类的接口转换为用户希望得到的另一个接口。它使原本不相同的接口得以协同工作。 速记关键字 转换接…

伦敦金短线好还是长线好

在伦敦金投之中&#xff0c;长期有一个争论很久的问题&#xff0c;那就是伦敦金投资究竟是长线好还是短线好&#xff1f;不同的投资者对这个问题有不同的看法&#xff0c;一般认为&#xff0c;伦敦金投资比较适合短线交易。笔者也将讨论这个问题&#xff0c;看看伦敦金投资是不…