java第十六章:坦克大战1.0
java第十六章:坦克大战1.0
java绘图坐标体系
像素
像素是一个密度单位,厘米是一个长度单位,二者无法比较!
java绘图原理
1.Component类提供了两个和绘图相关最重要的方法:
(1):paint(Graphics g):绘制组件的外观
(2):repaint():刷新组件的外观
2.当组件第一次在屏幕显示的时候,程序会自动的调用paint()方法来绘制组件
3.在以下情况paint()将会被调用:
(1):窗口最小化,再最大化
(2):窗口的大小发生变化
(3):repaint方法被调用
Graphics类常用方法
- 画直线:drawLine(int x1,int y1,int x2,int y2)
- 画矩形边框:drawRect(int x,int y,int width,int height)
- 画椭圆边框:drawOval(int x,int y,int width,int height)
- 填充矩形:fillRect(int x,int y,int width,int height)
- 填充椭圆:fillOval(int x,int y,int width,int height)
- 画图片:drawImage(Image img,int x,int y,this(当前对象))
- 画字符串:drawString(String str,int x,int y)
- 设置画笔的字体:setFont(Font font)
- 设置画笔的颜色:setColor(Color c)
package com.lcz.draw;
import javax.swing.*;//1
import java.awt.*;
/**
* @author lcz
* @version 1.0
* 需求:
* //## Graphics类常用方法
*/
class MyFrame extends JFrame{//2
private JPanel jPanel;//3
public MyFrame(){//4
init();//4.1
this.setBounds(100,100,500,300);//4.2
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void init(){//5
jPanel = new MyPanel();//5.1
this.add(jPanel);//5.2
}
}
public class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {//Graphics相当于画笔,有各种方法
super.paint(g);//调用父类方法初始化界面
//- 画直线:drawLine(int x1,int y1,int x2,int y2)
//g.drawLine(10,10,100,100);
//- 画矩形边框:drawRect(int x,int y,int width,int height)
//g.drawRect(10,10,100,100);
//- 画椭圆边框:drawOval(int x,int y,int width,int height)
//g.drawOval(10,10,100,100);
//- 填充矩形:fillRect(int x,int y,int width,int height)
//g.setColor(Color.blue);
//g.fillRect(10,10,100,100);
//- 填充椭圆:fillOval(int x,int y,int width,int height)
//g.setColor(Color.red);
//g.fillOval(10,10,100,100);
//- 画图片:drawImage(Image img,int x,int y,this(当前对象))
//Image image = Toolkit.getDefaultToolkit().getImage(JPanel.class.getResource("/method1.png"));
//g.drawImage(image,10,10,172,200,this);
//- 画字符串:drawString(String str,int x,int y)
//字符串以第一个字的左下角为x,y
//g.setColor(Color.red);
//g.setFont(new Font("黑体",Font.BOLD,50));
//g.drawString("北京欢迎你",50,50);
//- 设置画笔的字体:setFont(Font font)
//- 设置画笔的颜色:setColor(Color c)
}
}
class Test{
public static void main(String[] args) {
new MyFrame();
}
}
坦克大战1.0
初始化窗口并绘制游戏区域
Hero
package com.lcz.tankgame;
/**
* @author lcz
* @version 1.0
* 需求:
* Hero类
*/
public class Hero extends Tank{
public Hero(int x, int y) {
super(x, y);
}
}
MyPanel
package com.lcz.tankgame;
import javax.swing.*;
import java.awt.*;
/**
* @author lcz
* @version 1.0
* 需求:
* 坦克大战的绘图区域
*/
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.setColor(Color.BLUE);
g.fillRect(0,0,500,750);//填充矩形,默认黑色
}
}
Tank
package com.lcz.tankgame;
/**
* @author lcz
* @version 1.0
* 需求:
* 基类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;
}
}
TankGame01
package com.lcz.tankgame;
import com.lcz.draw.MyPanel;
import javax.swing.*;//1
import java.awt.*;
/**
* @author lcz
* @version 1.0
*/
public class TankGame01 extends JFrame {//2
private JPanel jPanel;//3
public TankGame01(){//4
init();//4.1
this.setBounds(0,0,1000,750);//4.2
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void init(){//5
jPanel = new MyPanel();//5.1
this.add(jPanel);//5.2
}
}
class Test{
public static void main(String[] args) {
TankGame01 tankGame01 = new TankGame01();
}
}
绘制坦克
在MyPanel类中编写drawTank方法,并在MyPanel类的paint方法中调用即可
思路:将绘制坦克封装为方法。
传入参数:int x,int y,Graphics g,int direct,int type
根据switch(direct){
}根据方向不同:画出不同坦克
根据switch(type){
}根据类型不同:决定画笔颜色
public void paint(Graphics g) {
super.paint(g);;
//g.setColor(Color.BLUE);
g.fillRect(0,0,1000,750);//填充矩形,默认黑色
drawTank(hero.getX(),hero.getY(),g,0,0);
}
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;
default:
System.out.println("暂时没有处理");
}
}
小球移动案例:
事件处理机制:
事件源和事件:
事件监听器:
示意图:
MyPanel2
package com.lcz.schoolwork.GUI.ballmove;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* @author lcz
* @version 1.0
*/
public class MyPanel2 extends JPanel implements KeyListener {//键盘监听器
//小球坐标初始化
int x = 10;
int y = 10;
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x,y,50,50);
}
@Override
public void keyTyped(KeyEvent e) {//响应:键盘输出字符
}
@Override
public void keyPressed(KeyEvent e) {//响应:键盘按下
//KeyEvent.VK_DOWN (int):为一个键的十六进制的编码值
if(e.getKeyCode() == KeyEvent.VK_DOWN)
y++;
else if(e.getKeyCode() == KeyEvent.VK_UP)
y--;
else if(e.getKeyCode() == KeyEvent.VK_LEFT)
x--;
else if(e.getKeyCode() == KeyEvent.VK_RIGHT)
x++;
//重绘
repaint();
}
@Override
public void keyReleased(KeyEvent e) {//响应:键盘释放
}
}
Test
package com.lcz.schoolwork.GUI.ballmove;
/**
* @author lcz
* @version 1.0
*/
public class Test {
public static void main(String[] args) {
new BallMove();
}
}
BallMove
package com.lcz.schoolwork.GUI.ballmove;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyListener;
/**
* @author lcz
* @version 1.0
*/
public class BallMove extends JFrame {
JPanel jPanel;
public BallMove() throws HeadlessException {
init();
this.setBounds(100,100,500,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void init(){
jPanel = new MyPanel2();
this.add(jPanel);
this.addKeyListener((KeyListener) jPanel);
}
}
绘制不同方向的坦克
思路:想要绘制不同方向的坦克,把坦克方向作为变量:做为Tank类的私有属性并提供getter和setter方法
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,y,60,10,false);//画出坦克左边轮子
g.fill3DRect(x,y + 30,60,10,false);//画出坦克右边轮子
g.fill3DRect(x + 10,y + 10,40,20,false);//画出坦克盖子
g.fillOval(x + 20,y + 10,20,20);//画出坦克原型盖子
g.drawLine(x + 30,y + 20,x + 60,y + 20);//画出坦克炮筒
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,y,60,10,false);//画出坦克左边轮子
g.fill3DRect(x,y + 30,60,10,false);//画出坦克右边轮子
g.fill3DRect(x + 10,y + 10,40,20,false);//画出坦克盖子
g.fillOval(x + 20,y + 10,20,20);//画出坦克原型盖子
g.drawLine(x + 30,y + 20,x,y + 20);//画出坦克炮筒
break;
default:
System.out.println("暂时没有处理");
}
让坦克动起来
思路:
1.MyPanel类实现KeyListenner接口,重写相关方法响应键盘事件
2.w a s d对应不同逻辑:分为改变坦克方向、坦克进行移动(封装到Tank类的相关方法)
3.改变坦克方向:用坦克方向的setter方法即可
4.坦克移动的速度可以作为Tank类的私有属性并提供getter、setter方法,以后创建坦克时可以设置速度
核心代码
MyPanel类
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
//1.更改坦克方向
hero.setDirect(0);
//2.坦克移动:封装为方法
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) {
}
Tank类
private int speed = 1;//速度默认为 1
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
private int direct;//坦克方向:0 上 1 右 2 下 3 左
//坦克移动方法 上 右 下 左
public void moveUp(){//上
y -= speed;
}
public void moveRight(){//右
x += speed;
}
public void moveDown(){//下
y += speed;
}
public void moveLeft(){//左
x -= speed;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
本章作业:
分析:
- 因为敌人的坦克,是在MyPanel,所以我们的代码在MyPanel
- 因为敌人的坦克,后面有自己特殊的属性和方法,可以单开一个EnemyTank
- 敌人坦克数量多,可以放入到集合Vector,因为考虑多线程问题
EnemyTank
package com.lcz.tankgame.tankgame02;
/**
* @author lcz
* @version 1.0
* EnemyTank类
*/
public class EnemyTank extends Tank{
public EnemyTank(int x, int y) {
super(x, y);
}
}
MyPanel
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankSize = 3;
public MyPanel() {//初始化坦克相关属性
hero = new Hero(100,100);//初始化坐标位置
//hero.setSpeed(3);
//添加敌人坦克
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = new EnemyTank(100 * (i + 1),0);
enemyTank.setDirect(2);
enemyTanks.add(enemyTank);
}
}
//绘画默认调用方法
@Override
public void paint(Graphics g) {
super.paint(g);;
//g.setColor(Color.BLUE);
g.fillRect(0,0,1000,750);//填充矩形,默认黑色
drawTank(hero.getX(),hero.getY(),g,hero.getDirect(),1);
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = enemyTanks.get(i);
drawTank(enemyTank.getX(),enemyTank.getY(),g,enemyTank.getDirect(),0);
}
}
k = new EnemyTank(100 * (i + 1),0);
enemyTank.setDirect(2);
enemyTanks.add(enemyTank);
}
}
//绘画默认调用方法
@Override
public void paint(Graphics g) {
super.paint(g);;
//g.setColor(Color.BLUE);
g.fillRect(0,0,1000,750);//填充矩形,默认黑色
drawTank(hero.getX(),hero.getY(),g,hero.getDirect(),1);
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = enemyTanks.get(i);
drawTank(enemyTank.getX(),enemyTank.getY(),g,enemyTank.getDirect(),0);
}
}