4.9Java游戏项目练习

4.9Java游戏项目练习

目的

巩固之前学的Java的基础

基本功能的实现步骤

AWT和Swing是Java中常见的GUI(图形用户界面),但是Java很少用于桌面应用开发,所以无需学习这两门技术
MyGameFrame类:画游戏窗口
package com.lucifer.game;

import javax.swing.*; //需要导入的类
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
* @Description 飞机游戏的主窗口
* @Author Lucifer
*/
public class MyGameFrame extends JFrame {
   /**
    * 写一个方法用来在类里面加载窗口,初始化窗口
    */
   public void launchFrame(){
       /*给游戏窗口加一个标题---settitle*/
       this.setTitle("Make By Lucifer");
       /*窗口可视化---调用方法*/
       this.setVisible(true);
       /*给窗口设置大小---利用setSize方法*/
       this.setSize(600,600);
       /*窗口居中---调用方法*/
       this.setLocation(750,200);
       /*
       设置窗口的位置,根据的是屏幕的x.y轴来设置。
       原点(0,0)位于屏幕右上角
       往下是x轴,往右是y轴
       */

       /*加一个匿名内部类*/
       this.addWindowListener(new WindowAdapter() {
           /*重写一个方法*/
           @Override
           /*正在运行的window窗口,所以是Closing*/
           public void windowClosing(WindowEvent e){
               /*结束虚拟机*/
               System.exit(0);
          }
      });
  }

再窗口中画图形和文本

窗口类主方法:paint方法

作用:

  • 做窗口的绘制

特点:

  • 自动被调用

  • g这个变量相当于一支画笔

实例:

/**
* @Description 飞机游戏的主窗口
* @Author Lucifer
*/
public class MyGameFrame extends JFrame {

   /*重写桌面绘制方法*/
   @Override
   public void paint(Graphics g){
       /*
       g本身带有颜色,形参对象是别人传过来的
       在下面来个g的颜色再别的地方再用g画笔就会直接更改
       所以有使用方法:
       用之前先保存,然后最后用完了再改回去---创建对象保存
       改字体的思想一样
        */
       Color c = g.getColor();
       Font f = g.getFont();

       /*画一条线,包括起点的坐标(横、纵坐标)和终点的(横、纵坐标)*/
       g.drawLine(100,100,300,300);
       /*画矩形的方法*/
       g.drawRect(100,100,300,300);
       /*画椭圆的方法*/
       g.drawOval(100,100,300,300);
       /*画实心的矩形*/
       g.fillRect(100,100,300,300);
       /*画字符串*/
       g.drawString("Lucifer",500,500);
       /*变颜色---这个Color是个静态的类,里面有些静态的变量,可以直接使用*/
       g.setColor(Color.BLUE);
       /*设置字体风格*/
       g.setFont(new Font("微软雅黑",Font.BOLD,50)); //形参为一个对象,实参也要创建一个对象去传入

       g.setColor(c);
       g.setFont(f);
  }

用ImageIO实现图片加载技术(0.3版)

过程:

  • 将图片加载的方法封装到GameUtil工具类中,便于以后直接调用

实例:

import javax.swing.*; //需要导入的类
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
* @description 飞机游戏的主窗口
* @author Lucifer
*/
public class MyGameFrame extends JFrame {

   /*加载图片---创建对象加载*/
   Image Marks = GameUtil.getImage("images/staticPicture.jpg");

   /*重写桌面绘制方法*/
   @Override
   public void paint(Graphics g){
       /*
       g本身带有颜色,形参对象是别人传过来的
       在下面来个g的颜色再别的地方再用g画笔就会直接更改
       所以有使用方法:
       用之前先保存,然后最后用完了再改回去---创建对象保存
       改字体的思想一样
        */
       Color c = g.getColor();
       Font f = g.getFont();

       /*画一条线,包括起点的坐标(横、纵坐标)和终点的(横、纵坐标)*/
       g.drawLine(100,100,300,300);
       /*画矩形的方法*/
       g.drawRect(100,100,300,300);
       /*画椭圆的方法*/
       g.drawOval(100,100,300,300);
       /*画实心的矩形*/
       g.fillRect(100,100,300,300);
       /*画字符串*/
       g.drawString("Lucifer",500,500);
       /*变颜色---这个Color是个静态的类,里面有些静态的变量,可以直接使用*/
       g.setColor(Color.BLUE);
       /*设置字体风格*/
       g.setFont(new Font("微软雅黑",Font.BOLD,50)); //形参为一个对象,实参也要创建一个对象去传入
       /*画出图片*/
       g.drawImage(Marks,50,50,null);

       g.setColor(c);
       g.setFont(f);
  }
工具类
package com.lucifer.game;

import javax.imageio.ImageIO;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

/**
* 一个工具类
* @author Lucifer
*/
public class GameUtil {
   //私有化工具类构造器
   private GameUtil(){
  }

   /**
    * 返回指定路径文件的图片对象
    * @param path
    * @return
    */
   /*工具类的方法*/
   public static Image getImage(String path){
       BufferedImage bi = null;
       try {
           URL u = GameUtil.class.getClassLoader().getResource(path);
           bi = ImageIO.read(u);
      }catch (IOException e){
           e.printStackTrace();
      }
       return bi;
  }
}

多线程和内部类实现动画效果

方法:

  • 再MyGameFrame类中定义"重画窗口线程PaintThread类"

  • 将PaintThread定义成内部类

实例:

    /*
   定义一个内部类
   好处:
   直接使用外部类的属性
    */
   class PaintThread extends Thread{

       /*
       利用这个线程帮助我们反复重画窗口
        */
       /*重写父类的方法---内部类是子类*/
       @Override
       public void run(){
           while (true){

               System.out.println("窗口重画次数");
               /*调用外部类的repaint方法*/
               repaint(); //paint自动被系统调用,repaint可以自己调用---重画方法

               try{
                   Thread.sleep(40); //单位是毫秒
              }catch (InterruptedException e){
                   e.printStackTrace();
              }
               /*
               try中间内容没细说
                */
          }
      }
  }
package com.lucifer.game;

import javax.swing.*; //需要导入的类
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
* @description 飞机游戏的主窗口
* @author Lucifer
*/
public class MyGameFrame extends JFrame {

   /*加载图片---创建对象加载*/
   Image Marks = GameUtil.getImage("images/staticPicture.jpg");
   /*给个背景图片---动图皮卡丘*/
   Image Pkq = GameUtil.getImage("Images/big.gif");
   /*利用变量让Marks动起来*/
   int MarksX = 50, MarksY = 50;

   /*重写桌面绘制方法*/
   @Override
   public void paint(Graphics g){
       /*
       g本身带有颜色,形参对象是别人传过来的
       在下面来个g的颜色再别的地方再用g画笔就会直接更改
       所以有使用方法:
       用之前先保存,然后最后用完了再改回去---创建对象保存
       改字体的思想一样
        */
//       Color c = g.getColor();
//       Font f = g.getFont();
//
//       /*画一条线,包括起点的坐标(横、纵坐标)和终点的(横、纵坐标)*/
//       g.drawLine(100,100,300,300);
//       /*画矩形的方法*/
//       g.drawRect(100,100,300,300);
//       /*画椭圆的方法*/
//       g.drawOval(100,100,300,300);
//       /*画实心的矩形*/
//       g.fillRect(100,100,300,300);
//       /*画字符串*/
//       g.drawString("Lucifer",500,500);
//       /*变颜色---这个Color是个静态的类,里面有些静态的变量,可以直接使用*/
//       g.setColor(Color.BLUE);
//       /*设置字体风格*/
//       g.setFont(new Font("微软雅黑",Font.BOLD,50)); //形参为一个对象,实参也要创建一个对象去传入
       /*画出皮卡丘*/
       g.drawImage(Pkq,0,0,null);
       /*画出图片---Marks*/
       g.drawImage(Marks,MarksX,MarksY,null);
       MarksX++;
       MarksY++;

双缓存技术使用说明:

GameObject类设计

目的:

  • 因为制作的内容有很多共性,设计一个GameObject类作为所有物体的父类,方便编程

共性:

  • 有图片的

  • 物体是有坐标的

  • 移动的速度

  • 物体的宽度和高度

所以需要定义一个父类,把这些属性放进去,然后以后要使用就去继承即可

实例:

package com.lucifer.game;

import java.awt.*;

/**
* 游戏物体的父类
* @author Lucifer
*/
public class GameObject {

   //列出他们需要的属性
   /*需要图片---对象*/
//   private Image img;
   Image img;
   /*需要坐标点---double类型*/
//   private double x,y;
   double x,y;
   /*他们的移动速度*/
//   private int speed;
   int speed;
   /*宽度和高度*/
//   private int width,height;
   int width,height;

//   //JavaBean方法
//   public void setImg(Image img){
//       this.img = img;
//   }
//
//   public Image getImg(){
//       return img;
//   }
//
//   public void setX(double x){
//       this.x = x;
//   }
//
//   public double getX(){
//       return x;
//   }
//
//   public void setY(double y){
//       this.y = y;
//   }
//
//   public double getY(){
//       return y;
//   }
//
//   public void setSpeed(int speed){
//       this.speed = speed;
//   }
//
//   public int getSpeed() {
//       return speed;
//   }
//
//   public void setHeight(int height) {
//       this.height = height;
//   }
//
//   public int getHeight() {
//       return height;
//   }
//
//   public void setWidth(int width) {
//       this.width = width;
//   }
//
//   public int getWidth() {
//       return width;
//   }

   /*定义物体画出自己的方法*/
   public void drawSelf(Graphics g){
       g.drawImage(img,(int)x,(int)y,null);
  }

   //为了方便使用加几个重载的构造器
   public GameObject(Image img, double x, double y, int speed, int width, int height){
       super();
       this.img = img;
       this.x = x;
       this.y = y;
       this.speed = speed;
       this.width = width;
       this.height = height;
  }

   public GameObject(Image img, double x, double y){
       super();
       this.img = img;
       this.x = x;
       this.y = y;
  }

   //无参构造器
   public GameObject(){
  }

   /**
    * 返回物体所在的矩形,便于后期的碰撞检测
    * @return
    */
   public Rectangle getRect(){
       return new Rectangle((int)x, (int)y,width,height);
  }
}
然后再写一个class重写里面需要用到的方法
package com.lucifer.game;

import java.awt.*;

/**
* 继承根类
* @author Lucifer
*/
public class Plane extends GameObject{

   /*重写父类方法*/
   /*
   因为这个属性用了private修饰符,所以不能直接重写
    */
   @Override
   public void drawSelf(Graphics g){
       g.drawImage(img,(int)x,(int)y,null);
       x++;
       y++;
  }

   /*重写构造器*/
   public Plane(Image img, double x, double y){
       this.img = img;
       this.x = x;
       this.y = y;
  }
}
最后在写一个类去调用
package com.lucifer.game;

import javax.swing.*; //需要导入的类
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
* @description 飞机游戏的主窗口
* @author Lucifer
*/
public class MyGameFrame extends JFrame {

   /*加载图片---创建对象加载*/
   Image Marks = GameUtil.getImage("images/staticPicture.jpg");
   /*给个背景图片---动图皮卡丘*/
   Image Pkq = GameUtil.getImage("Images/big.gif");
//   /*利用变量让Marks动起来*/
//   int MarksX = 50, MarksY = 50;
   /*
   因为定义了Plane的类来写方法,所以这里需要创建对象去调用方法
    */
   Plane p = new Plane(Marks,50,50);
   Plane p2 = new Plane(Marks,69,69);
   Plane p3 = new Plane(Marks,79,79);

   /*重写桌面绘制方法*/
   @Override
   public void paint(Graphics g){
       /*
       g本身带有颜色,形参对象是别人传过来的
       在下面来个g的颜色再别的地方再用g画笔就会直接更改
       所以有使用方法:
       用之前先保存,然后最后用完了再改回去---创建对象保存
       改字体的思想一样
        */
//       Color c = g.getColor();
//       Font f = g.getFont();
//
//       /*画一条线,包括起点的坐标(横、纵坐标)和终点的(横、纵坐标)*/
//       g.drawLine(100,100,300,300);
//       /*画矩形的方法*/
//       g.drawRect(100,100,300,300);
//       /*画椭圆的方法*/
//       g.drawOval(100,100,300,300);
//       /*画实心的矩形*/
//       g.fillRect(100,100,300,300);
//       /*画字符串*/
//       g.drawString("Lucifer",500,500);
//       /*变颜色---这个Color是个静态的类,里面有些静态的变量,可以直接使用*/
//       g.setColor(Color.BLUE);
//       /*设置字体风格*/
//       g.setFont(new Font("微软雅黑",Font.BOLD,50)); //形参为一个对象,实参也要创建一个对象去传入
//       /*画出皮卡丘*/
//       g.drawImage(Pkq,0,0,null);
//       /*画出图片---Marks*/
//       g.drawImage(Marks,MarksX,MarksY,null);
//       MarksX++;
//       MarksY++;
//
//       g.setColor(c);
//       g.setFont(f);
       //因为已经在对象里封装了方法,所以直接调用即可
       p.drawSelf(g);
       p2.drawSelf(g);
       p3.drawSelf(g);
       /*
       可以定义不同的对象
       后期可以把对象放进数组或者容器里
        */

  }

   /*
   定义一个内部类
   好处:
   直接使用外部类的属性
    */
   class PaintThread extends Thread{

       /*
       利用这个线程帮助我们反复重画窗口
        */
       /*重写父类的方法---内部类是子类*/
       @Override
       public void run(){
           while (true){

               System.out.println("窗口重画次数");
               /*调用外部类的repaint方法*/
               repaint(); //paint自动被系统调用,repaint可以自己调用---重画方法

               try{
                   Thread.sleep(40); //单位是毫秒
              }catch (InterruptedException e){
                   e.printStackTrace();
              }
               /*
               try中间内容没细说
                */
          }
      }
  }

   /**
    * 写一个方法用来在类里面加载窗口,初始化窗口
    */
   public void launchFrame(){
       /*给游戏窗口加一个标题---settitle*/
       this.setTitle("Make By Lucifer");
       /*窗口可视化---调用方法*/
       this.setVisible(true);
       /*给窗口设置大小---利用setSize方法*/
       this.setSize(600,600);
       /*窗口居中---调用方法*/
       this.setLocation(750,200);
       /*
       设置窗口的位置,根据的是屏幕的x.y轴来设置。
       原点(0,0)位于屏幕右上角
       往下是x轴,往右是y轴
       */

       /*加一个匿名内部类*/
       this.addWindowListener(new WindowAdapter() {
           /*重写一个方法*/
           @Override
           /*正在运行的window窗口,所以是Closing*/
           public void windowClosing(WindowEvent e){
               /*结束虚拟机*/
               System.exit(0);
          }
      });

       /*
       启动线程
        */
       new PaintThread().start(); //启动重画窗口的线程
  }

   //main方法调用上面的方法
   public static void main(String[] args) {
       MyGameFrame mgf = new MyGameFrame();
       mgf.launchFrame();
  }
}
It's a lonely road!!!
原文地址:https://www.cnblogs.com/JunkingBoy/p/14638844.html