黑马程序员技术交流社区

标题: 自己用java写的控制台骑士飞行棋小游戏 [打印本页]

作者: hfutWL    时间: 2016-9-11 17:27
标题: 自己用java写的控制台骑士飞行棋小游戏
以前有看过C#编程中有一个骑士飞行棋的小案例,一直想用java语言来实现,但是java不支持控制台打印有颜色的字符,效果没有C#的好。后来看到java可以使用 jansi-1.11.jar包来打印有颜色的字符。所以抽空写了下这个骑士飞行棋的小游戏。其实主要是练习数组和循环的知识,在C#编程中也是为了巩固数组和循环知识而拿来练习的。

程序实现了部分功能,应该还有点小bug,有兴趣的可以继续完善。下图是程序效果图。
注:只能在cmd环境下运行,在eclipse下运行不出效果。程序就是用editplus写的。
附件有程序和jansi-1.11.jar包,把jansi包加入classpath中就可以用了。

主程序:KnightChess.java
[Java] 纯文本查看 复制代码
/**
1.先将jansi-1.11.jar文件的路径加入classpath中,里面包含可以改变控制台打印字符颜色的方法.
2.导入需要用到的包
*/
import org.fusesource.jansi.AnsiConsole;
import static org.fusesource.jansi.Ansi.*;
import java.io.IOException;
import java.util.Scanner;

public class KnightChess {
        //游戏只有两个玩家,定义两个玩家对象
        public static Player p1;
        public static Player p2;
        //定义一个二维数组来保存地图
        public static String[][] map;
        //定义一个获取键盘输入的对象
        public static Scanner sc = new Scanner(System.in);
        //主函数
        public static void main(String[] args) throws Exception{
                System.out.println("---------------------------------------------------------------------------");
                System.out.println("-----------------------------骑士飞行棋------------------------------------");
                System.out.println("---------------------------------------------------------------------------");
                System.out.println("---------------------------------------------------------------------------");
                System.out.println("游戏规则:有两名玩家,已定义成甲和乙。甲、乙玩家轮流"
                + "掷骰子,谁先到终点就赢得比赛。\r\n甲和乙掷骰子都只需要按enter键.");
                //创建两个玩家甲 乙
                p1 = new Player("甲");
                p2 = new Player("乙");
                //初始化地图
                initMap();
                //开始游戏
                GameBegin();
                //为了线程阻塞,停留在结束画面       
                System.out.println("-----------游戏结束-----------");
        }
        //初始化地图
        public static void initMap(){
                //地图是一个21行30列的二维数组
                //给二维数组的每个位置赋值,使打印时显示迂回前进的地图
                map = new String[21][30];
                for(int i = 0; i < map.length; i++){       
                        for(int j = 0; j < 30; j++){
                                map[j] = "□";
                        }
                        if(i % 4 == 1){
                                for(int j = 0; j < 29; j++){
                                        map[j] = "我";
                                }
                        }
                        if(i % 4 == 3){
                                for(int j = 1; j < 30; j++){
                                        map[j] = "我";
                                }
                        }
                }
                //初始化有魔法功能的特殊位置
                magicMap();
                //甲在数组中的位置
                map[p1.posY][p1.posX] = p1.getName();
                //乙在数组中的位置
                map[p2.posY][p2.posX] = p2.getName();
        }
       
        public static void display()throws Exception{
                //产生一个进程调用控制台的命令用来清屏
                new ProcessBuilder("cmd", "/C", "cls").inheritIO().start();
                //因为这里不加这个线程睡眠的语句,打印出的地图有问题,所以加了
                //应该是上面进程与下面打印的并行进行,前面打印出的字符都被清屏的进程给清掉了.
                Thread.sleep(30);
                AnsiConsole.systemInstall();
                //根据数组中存储的不同字符打印出不同的字符
                for(int i = 0; i < map.length; i++){
                        for(int j = 0; j < map[0].length; j++){
                                String shape = map[j];
                                switch (shape) {
                                case "□":
                                        System.out.print(ansi().render("@|white " + shape +"|@"));
                                        break;
                                case "○":
                                        System.out.print(ansi().render("@|red " + shape +"|@"));
                                        break;
                                case "▽":
                                        System.out.print(ansi().render("@|blue " + shape +"|@"));
                                        break;
                                case "△":
                                        System.out.print(ansi().render("@|yellow " + shape +"|@"));
                                        break;
                                case "☆":
                                        System.out.print(ansi().render("@|cyan " + shape +"|@"));
                                        break;
                                case "◇":
                                        System.out.print(ansi().render("@|white " + shape +"|@"));
                                        break;
                                case "甲":
                                        System.out.print(ansi().render("@|magenta " + shape +"|@"));
                                        break;
                                case "乙":
                                        System.out.print(ansi().render("@|yellow " + shape +"|@"));
                                        break;
                                default:
                                        System.out.print("  ");
                                        break;
                                }               
                        }
                        System.out.println();
                }
        }
        //游戏开始
        public static void GameBegin() throws Exception{
                while(true){
                        if(Player.flag == "结")
                                break;
                        System.out.println("请甲开始掷骰子");
                        //接收键盘输入,按回车后,执行下一条语句.
                        sc.nextLine();
                        //甲玩游戏
                        p1.play();
                        if(Player.flag == "结")
                                break;
                        System.out.println("请乙开始掷骰子");
                        sc.nextLine();
                        //乙玩游戏
                        p2.play();
                }
        }
        //自定义了不同魔法功能特殊地点的位置
        public static void magicMap(){

                int[][] mine = {{0,4},{2,9},{4,20},{6,29},{8,10},{10,17},{12,0},{20,5}};
                int[][] luckplace = {{0,5},{4,10},{8,13},{10,20},{16,16},{18,20},{20,11},{14,15}};
                int[][] back = {{0,7},{2,8},{6,10},{8,7},{10,7},{16,20},{12,8},{14,19}};
                int[][] forword = {{14,7},{16,2},{18,13},{20,26},{10,7},{8,0},{6,20},{20,10}};
                foreach(luckplace,"☆",map);
                foreach(forword,"△",map);
                foreach(back,"▽",map);
                foreach(mine,"○",map);
        }
        //给地图设置特殊地点符号
        public static void foreach (int[][] arr, String symbol, String[][] map) {
                for (int i = 0; i < arr.length; i++) {
                        int x = arr[0];
                        int y = arr[1];
                        map[x][y] = symbol;
                }
        }
}




Play类:Player.java
[Java] 纯文本查看 复制代码
public class Player {
        //玩家的姓名
        private String name;
        //玩家在地图中的位置,posX代表玩家所在的列数,posY代表玩家所在的行数.
        public int posX;
        public int posY;
        //定义一个长度为2的数组来存储玩家的位置
        public int[] point = new int[2];
        //一个判断玩家所在位置魔法功能的旗标
        public static String flag;
        public String getName(){
                return name;
        }
        //初始化玩家姓名的构造方法
        public Player(String name){
                this.name = name;
        }
        /**
        玩家玩游戏的方法
        */
        public void play() throws Exception{
                //随机生成1-6之间的数,模拟掷骰子
                int temp = Dice.getNum();       
                //玩家前进temp步数,并返回前进后位置,此处只算好玩家前进后位置,并没有将玩家移动到该位置
                point = forwordLogic(posX,posY,temp);
                //获得玩家所在列数
                posX = point[0];
                //获得玩家所在行数
                posY = point[1];
                //假如得到自己定义的结束信息,将flag赋值为结
                if(posY == 1 && posX == 1)
                {
                        KnightChess.map[1][1] = "结";
                        flag = "结";
                }
                //判断玩家是否到达终点,获取玩家所在位置的符号
                else if(posY < 21 && posX < 30){
                        flag = KnightChess.map[posY][posX];
                }
               
                //根据前面算出的玩家位置,得到将要到达位置的字符类型,并执行相应的操作,得到最终的地址
                point = magicExecute(posX,posY);
                //获得玩家最终所在列数
                posX = point[0];
                //获得玩家最终所在行数
                posY = point[1];
                //初始化地图,为了消除前面对地图数组赋值产生的改变
                KnightChess.initMap();
                //显示地图
                KnightChess.display();
                //输出掷骰子的结果
                System.out.print(name + "投掷出了数字:" + temp + "\t");

                //通过switch case语句,根据玩家所处位置输出相应的语句
                switch (flag) {
                case "☆":
                        System.out.println(name + "搭上火箭了,前进10格!!!!");
                        break;
                case "△":
                        System.out.println(name + "龙卷风!!前进5格");
                        break;
                case "○":
                        System.out.println(name + "踩到地雷了,给我直接回到原点!!!!");
                        break;
                case "▽":
                        System.out.println(name + "脚底打滑,后退5格!!!!");
                        break;       
                case "结":
                        System.out.println(name + "恭喜你!!赢得了比赛!!");
                default:
                        break;       
                }

        }
        /**
        判断所处位置的符号,根据不同符号执行不同的动作
        */
        public int[] magicExecute(int posX, int posY){
                if(flag == "☆"){
                        point = forwordLogic(posX,posY,10);                                //前进10格
                }
                if(flag == "△"){
                        point = forwordLogic(posX,posY,5);                                //前进5格
                }
                if(flag == "○"){
                        point = new int[]{0,0};                                                        //回到原点
                }
                if(flag == "▽"){
                        point = backLogic(posX,posY);                                        //后退5格,后退步数方法内写死了
                }
                return point;
        }
        /**
        实现棋子前进的方法
        */
        public int[] forwordLogic(int posX, int posY, int step){
               
                if(posY % 4 == 0){                                                //玩家位于第0 4 8 12 16 20行
                        if(posX + step < 30){                                //玩家前进step步后依然在本行
                                posX += step;
                        }
                        else if(posX + step == 30){                        //玩家前进step步后推进1行,刚好位于转弯点
                                posX = 29;
                                posY += 1;
                        }
                        else{                                                                //玩家前进step步后推进了2行
                                posY += 2;
                                posX = 60 - posX - step;
                        }
                }
                else if(posY % 4 == 1){                                        //玩家位于第1 5 9 13 17行,也就是在转折点,所以肯定进入下一行
                        posY += 1;
                        posX = 30 - step;

                }
                else if(posY % 4 == 2){                                        //玩家位于第2 6 10 14 18行,前进时列数posX的值减去step
                        if(posX - step > -1){                                //依然有三种情况,分析和前面相同
                                posX -= step;
                        }else if(posX - step == -1){
                                posY += 1;
                                posX = 0;
                        }else{
                                posY += 2;
                                posX = step - posX - 2;
                        }
                }
                else if(posY % 4 == 3){                                        //玩家位于第3 7 11 15 19行,前进后行数一定加1,并且列数posX的变化方向改变
                        posY += 1;
                        posX = posX + step - 1;
                }
                if(posY < 21 && posX < 30){                                //当玩家没有到达终点,返回point数组,存储了玩家位置信息
                        point[0] = posX;
                        point[1] = posY;               
                }else{                                                                        //当玩家到达终点,将玩家的位置设置到点(1,1),并返回数组point
                        point[0] = 1;
                        point[1] = 1;
                }
                return point;
        }
        /**
        实现棋子后退的方法
        逻辑刚好与前进的相反
        */
        public int[] backLogic(int posX, int posY){
                int backStep = 5;
                if(posY % 4 == 0){
                        if(posX - backStep > -1){
                                posX -= backStep;
                        }else if(posX - backStep == -1){
                                posY -= 1;
                                posX = 0;
                        }else{
                                posY += 2;
                                posX = backStep - posX - 2;
                        }
                }
                else if(posY % 4 == 1){
                        posY += 1;
                        posX = posX - backStep + 1;
                }
                else if(posY % 4 == 2){
                        if(posX + backStep < 30){
                                posX += backStep;
                        }else if(posX + backStep == 30){
                                posX = 29;
                                posY += 1;
                        }else{
                                posY += 2;
                                posX = 60 - posX - backStep;
                        }
                }
                else if(posY % 4 == 3){
                        posY += 1;
                        posX = posX + backStep - 1;
                }
                point[0] = posX;
                point[1] = posY;
                return point;
        }
}




骰子类:Dice.java
[Java] 纯文本查看 复制代码
/**
1.骰子类,里面方法定义成static当成工具类
2.产生1-6的随机数
*/
public class Dice {
        public static int getNum(){
                return (int)(Math.random() * 6 + 1);
        }
}

图片.png (83.07 KB, 下载次数: 9)

骑士飞行棋

骑士飞行棋

jansi-1.11.rar

101.32 KB, 下载次数: 53

可以在控制台打印有颜色字符的jar包

骑士飞行棋.rar

8.58 KB, 下载次数: 38

源码


作者: 黑马程序员_鹿峣    时间: 2016-11-2 14:59
迷糊




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2