Java学习-第一部分-第二阶段-项目实战:坦克大战【1】

坦克大战【1】

笔记目录:(https://www.cnblogs.com/wenjie2000/p/16378441.html)

坦克大战游戏

为什么写这个项目
✔好玩
✔涉及到java各个方面的技术

  1. java面向对象编程
  2. 多线程
  3. 文件i/o操作
  4. 数据库

✔巩固旧知识,学习新知识

写项目前的提醒

  1. 编写坦克大战游戏,你需要有一定的java基础,是完全可以听懂的,最核心的部分一起完成。

  2. 记住一点:成为一个编程高手的秘诀就是:思考------编程-----思考------编程

如何讲解这个项目,授课的原则:

  1. 努力做到通俗易懂。

  2. 宁肯罗嗦一点,也不遗漏细节。

  3. 项目是从小到大的过程,每个完整的项目被分解成不同的版本,从1.0到1.1.….最后版,随版本的增加,将新的功能和新的知识点融入到项目中,整个过程是循序渐进的。让大家轻松的学习,高效的掌握java技术。

    image

java绘图坐标体系

●坐标体系-介绍

下图说明了Java坐标系。坐标原点位于左上角,以像素为单位。在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。

image

坐标体系-像素

  1. 绘图还必须要搞清一个非常重要的概念-像素个个像素等于多少厘米?
  2. 计算机在屏幕上显示的内容都是由屏幕上的每一个像素组成的。例如,计算机显示器的分辨率是800×600,表示计算机屏幕上的每一行由800个点组成,共有600行,整个计算机屏幕共有480 000个像素。像素是一个密度单位,而厘米是长度单位,两者无法比较

java绘图技术

介绍-快速入门

先给大家写一个小案例,在面板上画一个小圆,然后借这个案例,来讲解java绘图技术原理。

import javax.swing.*;
import java.awt.*;

public class DrawCircle extends JFrame {//JFrame对应窗口,可以理解成是一个画框
    //定义一个面板
    private MyPanel mp = null;
    public static void main(String[] args) {
        new Te();
        System.out.println("退出程序...");
    }
    public DrawCircle() {//构造器
        //初始化面板
        mp = new MyPanel();
        //把面板放入到窗口(画框)
        this.add(mp);
        //设置窗口的大小
        this.setSize(400,300);
        ///当点击窗口的小x,程序完全退出.
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);//可以显示
    }
}

//1.先定义一个MyPanel,继承JPanel类,画图形,就在面板上画
class MyPanel extends JPanel {
    //说明:
    //1.MyPanel对象就是一个画板
    //2.Graphics g把g理解成一支画笔
    //3.Graphics提供了很多绘图的方法
    //Graphics g
    @Override
    public void paint(Graphics g) {//绘图方法
        super.paint(g);//调用父类的方法完成初始化
        System.out.println("调用了paint方法");
        //画出一个圆形.
        g.drawOval(10, 10, 100, 100);
    }
}

绘图原理

✔Component类提供了两个和绘图相关最重要的方法:

  1. paint(Graphics g)绘制组件的外观

  2. repaint()刷新组件的外观。

✔当组件第一次在屏幕显示的时候,程序会自动的调用paint()方法来绘制组件。

✔在以下情况paint()将会被调用:

  1. 窗口最小化再最大化
  2. 窗口的大小发生变化
  3. repaint方法被调用

✔思考题:如何证明上面的三种情况,会调用paint()方法

Graphics类

Graphics类你可以理解就是画笔,为我们提供了各种绘制图形的方法:[参考jdk帮助文档]

  1. 画直线drawLine(int x1,int y1,int x2,int y2)

  2. 画矩形边框drawRect(int x, int y, int width, int height)

  3. 画椭圆边框drawOval(int x, int y, int width, int height)

  4. 填充矩形 fillRect(int x, int y, int width, int height)

  5. 填充椭圆fillOval(int x, int y, int width, int height)

  6. 画图片drawlmage(lmage img, int x, int y, ..)

  7. 画字符串drawString(String str, int x, int y)

  8. 设置画笔的字体setFont(Font font)

  9. 设置画笔的颜色setColor(Color c)

import javax.swing.*;
import java.awt.*;


public class DrawCircle extends JFrame {//JFrame对应窗口,可以理解成是一个画框
    //定义一个面板
    private MyPanel mp = null;
    public static void main(String[] args) {
        new Te();
        System.out.println("退出程序...");
    }
    public DrawCircle() {//构造器
        //初始化面板
        mp = new MyPanel();
        //把面板放入到窗口(画框)
        this.add(mp);
        //设置窗口的大小
        this.setSize(400,300);
        ///当点击窗口的小x,程序完全退出.
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);//可以显示
    }
}

//1.先定义一个MyPanel,继承JPanel类,画图形,就在面板上画
class MyPanel extends JPanel {
    //说明:
    //1.MyPanel对象就是一个画板
    //2.Graphics g把g理解成一支画笔
    //3.Graphics提供了很多绘图的方法
    //Graphics g
    @Override
    public void paint(Graphics g) {//绘图方法
        super.paint(g);//调用父类的方法完成初始化
        System.out.println("调用了paint方法");

        //演示绘制不同的图形..
        //1. 画直线drawLine(int x1,int y1,int x2,int y2)
//        g.drawLine(10,10,100,100);
        //2. 画矩形边框drawRect(int x, int y, int width, int height)
//        g.drawRect(10,10,100,100);
        //3. 画椭圆边框drawOval(int x, int y, int width, int height)
//        g.drawOval(10, 10, 100, 100);
        //4. 填充矩形 fillRect(int x, int y, int width, int height)
//        g.setColor(Color.BLUE);
//        g.fillRect(10,10,100,100);
        //5. 填充椭圆fillOval(int x, int y, int width, int height)
//        g.setColor(Color.red);
//        g.fillOval(10,10,100,100);
        //6. 画图片drawlmage(lmage img, int x, int y, ..)
//        Image image = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/张文杰.jpg"));
//        g.drawImage(image,10,10,150,200,this);
        //7. 画字符串drawString(String str, int x, int y)
//        g.setColor(Color.red);
//        g.setFont(new Font("行书",Font.BOLD,50));
//        g.drawString("你好",100,50);//x,y对应字符串左下角位置
        //8. 设置画笔的字体setFont(Font font)
        //9. 设置画笔的颜色setColor(Color c)
    }
}

绘出坦克

坦克大战游戏中,我们会用到坦克,现在我们就利用java绘图技术来画出一个小坦克,完成我们的坦克大战游戏1.0版本!

image

Tank//坦克位置

public class Tank {
    //坦克左上角坐标
    private int x;
    private int y;

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

Hero//玩家坦克

public class Hero extends Tank{
    public Hero(int x, int y) {
        super(x, y);
    }
}

MyPanel//面板

import javax.swing.*;
import java.awt.*;

public class MyPanel extends JPanel {
    Hero hero=null;//定义我的坦克
    public MyPanel(){
        hero=new Hero(100,100);//初始化自己的坦克位置
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0,0,1000,750);//黑色背景

        //画出坦克
        drawTank(hero.getX(),hero.getY(),g,0,1);
    }

    /**
     *
     * @param x 坦克左上角x坐标
     * @param y 坦克左上角y坐标
     * @param g 画笔
     * @param direct 坦克方向(上下左右)
     * @param type 坦克类型
     */
    public void drawTank(int x,int y,Graphics g,int direct,int type){

        switch (type){
            case 0://我们的坦克
                g.setColor(Color.cyan);
                break;
            case 1://敌人的坦克
                g.setColor(Color.yellow);
                break;
        }
        //根据坦克方向,绘制坦克
        switch (direct){
            case 0://向上
                g.fill3DRect(x,y,10,60,false);//画出坦克左边轮子
                g.fill3DRect(x+30,y,10,60,false);//画出坦克右边轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出坦克盖子
                g.fillOval(x+10,y+20,20,20);//画出圆形盖子
                g.drawLine(x+20,y+30,x+20,y);//画出炮筒
                break;
            case 1:
            case 2:
            case 3:
        }
    }
}

HspTankGame01//窗体

import javax.swing.*;

public class HspTankGame01 extends JFrame {
    MyPanel mp=null;
    public static void main(String[] args) {
        new HspTankGame01();
    }

    public HspTankGame01() {
        mp=new MyPanel();
        this.add(mp);
        this.setSize(1000,750);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

java事件处理机制

事件处理机制-看个问题

请大家看一个小程序。(BallMove.java)怎样让小球受到键盘的控制,上下左右移动.

image

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class BallMove extends JFrame{//窗口
    MyPanel mp=null;
    public static void main(String[] args) {
        new BallMove();
    }
    public BallMove(){
        mp=new MyPanel();
        this.add(mp);
        this.setSize(400,300);
        //窗口JFrame对象可以监听键盘事,即可以监听到面板发生的键盘事件
        this.addKeyListener(mp);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

//面板,可以画出小球
//KeyListener是监听器,可以监听键盘事件
class MyPanel extends JPanel implements KeyListener {
    //为了让小球可以移动,把他的左上角的坐标(x,y)设置变量
    int x = 10;
    int y =10;
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillOval(x,y,20,20);
    }

    //有字符输出,该方法就会触发
    @Override
    public void keyTyped(KeyEvent e) {

    }

    //当某个键按下,该方法触发
    @Override
    public void keyPressed(KeyEvent e) {
        //System.out.println((char)e.getKeyCode()+"被按下");

        //根据用户按下的不同键,来处理小球的移动(上下左右)
        //在java中,会给每一个键,分配一个值(int)
        if(e.getKeyCode()==KeyEvent.VK_DOWN){//KeyEvent.VK_DOWN就是向下的箭头对应的code
            y++;
        }else if (e.getKeyCode()==KeyEvent.VK_UP){
            y--;
        }else if(e.getKeyCode()==KeyEvent.VK_RIGHT){
            x++;
        }else if(e.getKeyCode()==KeyEvent.VK_LEFT){
            x--;
        }
        //让面板重绘
        this.repaint();
    }

    //当某个键松开,被触发
    @Override
    public void keyReleased(KeyEvent e) {

    }
}

基本说明

java事件处理是采取"委派事件模型"。当事件发生时,产生事件的对象,会把此"信息”传递给"事件的监听者"(例:KeyListener)处理,这里所说的“信息"实际上就是java.awt.event事件类库里某个类所创建的对象,把它称为"事件的对象"(例:KeyEvent)。

请大家看一个示意图:

image

事件处理机制深入理解

  1. 前面我们提到几个重要的概念事件源,事件,事件监听器我们下面来全面的介绍它们。

  2. 事件源:事件源是一个产生事件的对象,比如按钮,窗回等。

  3. 事件:事件就是承载事件源状态改变时的对象,比如当键盘事件、鼠标事件、窗口事件等等,会生成一个事件对象,该对象保存着当前事件很多信息,比如KeyEvent对象有含义被按下键的Code值。java.awt.event包和javax.swing.event包中定义了各种事件类型

  4. 事件类型:查阅jdk文档

image

  1. 事件监听器接口:

    (1)当事件源产生一个事件,可以传送给事件监听者处理

    (2)事件监听者实际上就是一个类,该类实现了某个事件监听器接口比如前面我们案例中的MyPanle就是一个类,它实现了KeyListener接口,它就可以作为一个事件监听者,对接受到的事件进行处理

    (3)事件监听器接口有多种,不同的事件监听器接口可以监听不同的事件,一个类可以实现多个监听接口

    (4)这些接口在java.awt.event包和javax.swing.event包中定义。列出常用的事件监听器接口,查看jdk文档聚集了.

坦克大战游戏(1.0版)

绘制己方坦克(能够使用WASD移动)

绘制敌方坦克(颜色有差别,至少3个)//要想敌人的坦克移动,需要下一节的线程知识

Tank//坦克

package tankgame02;

public class Tank {
    //坦克左上角坐标
    private int x;
    private int y;
    private int direct;//坦克方向 0上 1右 2下 3左

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    private int speed=1;//坦克速度

    //上右下左移动方法
    public void moveUp(){
        y-=speed;
    }
    public void moveDown(){
        y+=speed;
    }
    public void moveLeft(){
        x-=speed;
    }
    public void moveRight(){
        x+=speed;
    }

    public int getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}

Hero//己方坦克

package tankgame02;

public class Hero extends Tank {
    public Hero(int x, int y) {
        super(x, y);
    }
}

EnemyTank//敌方坦克

package tankgame02;

public class EnemyTank extends Tank{
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

MyPanel//面板

package tankgame02;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Hashtable;
import java.util.Vector;

////为了监听键盘事件,实现KeyListener
public class MyPanel extends JPanel implements KeyListener {
    Hero hero = null;//定义我的坦克
    Vector<EnemyTank> enemyTanks = new Vector<>();//定义敌人坦克
    int enemyTankSize = 3;

    public MyPanel() {
        hero = new Hero(100, 100);//初始化自己的坦克位置
        for (int i = 0; i < enemyTankSize; i++) {//初始化敌人的坦克位置
            enemyTanks.add(new EnemyTank(100 * (i + 1), 0));
        }

//        hero.setSpeed(5);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//黑色背景

        //画出坦克
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);

        //画出敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            enemyTank.setDirect(2);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);
        }
    }

    /**
     * @param x      坦克左上角x坐标
     * @param y      坦克左上角y坐标
     * @param g      画笔
     * @param direct 坦克方向(上下左右)
     * @param type   坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direct, int type) {

        switch (type) {
            case 0://我们的坦克
                g.setColor(Color.cyan);
                break;
            case 1://敌人的坦克
                g.setColor(Color.yellow);
                break;
        }
        //根据坦克方向,绘制坦克
        switch (direct) {
            case 0://向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒
                break;
            case 1://右
                g.fill3DRect(x - 10, y + 10, 60, 10, false);//画出坦克左边轮子
                g.fill3DRect(x - 10, y + 40, 60, 10, false);//画出坦克右边轮子
                g.fill3DRect(x, y + 20, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 50, y + 30);//画出炮筒
                break;
            case 2://下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3://左
                g.fill3DRect(x - 10, y + 10, 60, 10, false);//画出坦克左边轮子
                g.fill3DRect(x - 10, y + 40, 60, 10, false);//画出坦克右边轮子
                g.fill3DRect(x, y + 20, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + -10, y + 30);//画出炮筒
                break;
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //处理WDSA键按下情况
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            //改变坦克方向
            hero.setDirect(0);
            //修改坦克坐标
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {
            hero.setDirect(1);
            hero.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
            hero.setDirect(3);
            hero.moveLeft();
        }
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

HspTankGame02//窗体

package tankgame02;

import javax.swing.*;

public class HspTankGame02 extends JFrame {
    MyPanel mp=null;
    public static void main(String[] args) {
        new HspTankGame02();
    }

    public HspTankGame02() {
        mp=new MyPanel();
        this.add(mp);
        this.setSize(1000,750);
        this.addKeyListener(mp);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
posted @ 2022-08-30 23:24  文杰2000  阅读(200)  评论(0编辑  收藏  举报