上一篇,我们已经画出了一辆坦克,但是我们的坦克不会动,本篇(看起来长实际内容不多的),我们就来实现如何让坦克移动,(最好再建一个包存放复制原来的java文件),因为我们是一步步更新的,一乱可能连原来的文件都改回不了…
首先我们要做的是事件监听和事件处理,给MyPanel类添加一个接口KeyListener,并实现方法
class MyPanel extends Panel implements KeyListener
{
//省略部分代码......
/*实现KeyListener接口的方法*/
//键入某个键时调用此方法。
public void keyTyped(KeyEvent e) {
}
//释放某个键时调用此方法
public void keyReleased(KeyEvent e) {
}
//按下某个键时调用此方法: A代表向左,W代表向上,D代表向右,S代表向下
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W)//向上
{
}
else if(e.getKeyCode() == KeyEvent.VK_D)//向下
{
}
else if(e.getKeyCode() == KeyEvent.VK_S)//向下
{
}
else if(e.getKeyCode() == KeyEvent.VK_A)//向左
{
}
//没有这行代码即使实现了移动操作页面也不会动的
this.repaint();//调用repaint()函数,来重绘页面
}
}
!!!要实现监听,还要注册监听事件
public class TankGame2 extends JFrame{
public TankGame2(){
//...
this.addKeyListener(mp);//注册监听事件
}
}
其中 public void keyPressed(KeyEvent e){…}是我们主要操作的方法,下面四个if语句是添加上去的,用于判断是按了哪个键,按这个节奏,if语句里面是不是该填写坐标移动来实现坦克的移动呢(y–,x++,…),但是考虑到之后的修改问题,我们还是把移动这一方法封装起来(好处后面会提到)。在Tank类定义一个变量 int speed=1;作为坦克的速度,再回到Hero类添加移动的方法,由于 Hero继承Tank类,所以Hero类也能访问speed。
class Hero extends Tank
{
public Hero(int x,int y)
{
super(x,y);
}
//坦克向上移动
public void moveUp()
{
y-=speed;
}
//坦克向右移动
public void moveRight()
{
x+=speed;
}
//坦克向下移动
public void moveDown()
{
y+=speed;
}
//坦克向左移动
public void moveLeft()
{
x-=speed;
}
}
(如果是y++,x++那样的形式控制速度,那要修改速度就会显得很麻烦,连续改几个,而定义speed的话修改速度只需修改speed的数值。)接着再到刚才if语句那里添加移动方法
class MyPanel extends Panel implements KeyListener
{//省略部分代码......
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W)//向上
{
this.hero.moveUp();
}
else if(e.getKeyCode() == KeyEvent.VK_D)//向下
{
this.hero.moveRight();
}
else if(e.getKeyCode() == KeyEvent.VK_S)//向下
{
this.hero.moveDown();
}
else if(e.getKeyCode() == KeyEvent.VK_A)//向左
{
this.hero.moveLeft();
}
这个时候,运行效果是这样的(页面被我放大来拍摄做gif的)
我们看到它可以移动,但左右移动跟螃蟹走一样,所以下一步是做出它向下还是向左向右,绘出坦克整体向哪个方向的图。
在Tank类中定义坦克方向,并添加setter和getter方法
class Tank
{//省略部分代码......
//坦克方向
//0表示上,1表示右,2表示下,3表示左
int direct=0;
public int getDerect() {
return direct;
}
public void setDerect(int derect) {
this.direct = derect;
}
//...
}
再往回添加添加代码和修改
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W)//向上
{
this.hero.setDirect(0);
this.hero.moveUp();
}
else if(e.getKeyCode() == KeyEvent.VK_D)//向右
{
this.hero.setDirect(1);
this.hero.moveRight();
}
else if(e.getKeyCode() == KeyEvent.VK_S)//向下
{
this.hero.setDirect(2);
this.hero.moveDown();
}
else if(e.getKeyCode() == KeyEvent.VK_A)//向左
{
this.hero.setDirect(3);
this.hero.moveLeft();
}
this.repaint();//调用repaint()函数,来重绘页面
}
再修改代码(上篇我们初始化是0,方向向上),由于我们要改变方向,灵活一点就改为this.hero.direct
class MyPanel extends Panel implements KeyListener{
public void paint(Graphics g){
//...
this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
}
}
接下来看方向改变后坦克如何画
有两种方式,一种还是以最左边矩形左上角为参照点画,但是可能效果不是令人特别满意,转动的变化略大,而如果以圆形中间的点为参照点,转动起来就比较自然了,不过坐标要计算得更精确哦,可以试试..这里我们
还是以左上角的点为参照点画向右的坦克
//画出坦克的函数
public void drawTank(int x,int y,Graphics g,int direct,int type)
{//省略....
case 0://....
case 1://炮筒向右
//画出上面矩形
g.fill3DRect(x, y, 30, 5,false);
//2.画出右边矩形
g.fill3DRect(x, y+15, 30, 5,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 20, 10,false);
//4.画出圆形
g.fillOval(x+10, y+5, 10, 10);
//5.画直线
g.drawLine(x+15, y+10, x+30, y+10);
break;
case 2://炮筒向下
//画出上面矩形
g.fill3DRect(x, y, 5, 30,false);
//2.画出右边矩形
g.fill3DRect(x+15, y, 5, 30,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 10, 20,false);
//4.画出圆形
g.fillOval(x+5, y+10, 10, 10);
//5.画直线
g.drawLine(x+10, y+15, x+10, y+30);
break;
case 3://炮筒向左
//画出上面矩形
g.fill3DRect(x, y, 30, 5,false);
//2.画出右边矩形
g.fill3DRect(x, y+15, 30, 5,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 20, 10,false);
//4.画出圆形
g.fillOval(x+10, y+5, 10, 10);
//5.画直线
g.drawLine(x+15, y+10, x, y+10);
break;
}
}
事实上画出向右的方向,向左的就容易画了,因为算对称,而上篇画了向上的坦克,画向下的只要改动直线就行了,改后效果如图
最后为了更好的阅读代码,我们把Tank类和Hero类剪切到一个Members.java文件,分为两个文件,最后附上完整代码:
Members.java
package com.TankGame1;
//坦克类
class Tank
{
//表示坦克的横坐标
int x=0;
//表示坦克的纵坐标
int y=0;
//坦克方向
//0表示上,1表示右,2表示下,3表示左
int direct=0;
public int getDirect() {
return direct;
}
public void setDirect(int derect) {
this.direct = derect;
}
//坦克速度
int speed=1;
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;
}
public Tank(int x,int y)
{
this.x=x;
this.y=y;
}
}
//我的坦克
class Hero extends Tank
{
public Hero(int x,int y)
{
super(x,y);
}
//坦克向上移动
public void moveUp()
{
y-=speed;
}
//坦克向右移动
public void moveRight()
{
x+=speed;
}
//坦克向下移动
public void moveDown()
{
y+=speed;
}
//坦克向左移动
public void moveLeft()
{
x-=speed;
}
}
TankGame2.java
package com.TankGame1;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
/*
* */
public class TankGame2 extends JFrame
{
MyPanel mp =null;
public static void main(String[] args)
{
TankGame2 tankgame1 = new TankGame2();
}
public TankGame2()
{
mp=new MyPanel();
this.addKeyListener(mp);
this.setVisible(true);
this.setSize(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(mp);
}
}
//我的面板
class MyPanel extends Panel implements KeyListener
{
//定义一个我的坦克
Hero hero =null;
public MyPanel()
{
hero =new Hero(100,100); //坦克的初始位置(10,10)
}
//重新paint
public void paint(Graphics g)
{
super.paint(g);
g.fillRect(0, 0, 1200, 900); //填充使背景变为黑色
this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
}
//画出坦克的函数
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:
//画出我的坦克(到时再封装成一个函数)
//1.画出左边的矩形
g.fill3DRect(x, y, 5, 30,false);
//2.画出右边矩形
g.fill3DRect(x+15, y, 5, 30,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 10, 20,false);
//4.画出圆形
g.fillOval(x+5, y+10, 10, 10);
//5.画直线
g.drawLine(x+10, y+15, x+10, y);
break;
case 1://炮筒向右
//画出上面矩形
g.fill3DRect(x, y, 30, 5,false);
//2.画出右边矩形
g.fill3DRect(x, y+15, 30, 5,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 20, 10,false);
//4.画出圆形
g.fillOval(x+10, y+5, 10, 10);
//5.画直线
g.drawLine(x+15, y+10, x+30, y+10);
break;
case 2://炮筒向下
//画出上面矩形
g.fill3DRect(x, y, 5, 30,false);
//2.画出右边矩形
g.fill3DRect(x+15, y, 5, 30,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 10, 20,false);
//4.画出圆形
g.fillOval(x+5, y+10, 10, 10);
//5.画直线
g.drawLine(x+10, y+15, x+10, y+30);
break;
case 3://炮筒向左
//画出上面矩形
g.fill3DRect(x, y, 30, 5,false);
//2.画出右边矩形
g.fill3DRect(x, y+15, 30, 5,false);
//3.画出中间矩形
g.fill3DRect(x+5, y+5, 20, 10,false);
//4.画出圆形
g.fillOval(x+10, y+5, 10, 10);
//5.画直线
g.drawLine(x+15, y+10, x, y+10);
break;
}
}
/*实现KeyListener接口的方法*/
//键入某个键时调用此方法。
public void keyTyped(KeyEvent e) {
}
//释放某个键时调用此方法
public void keyReleased(KeyEvent e) {
}
//按下某个键时调用此方法: a代表向左,w代表向上,d代表向右,s代表向下
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W)//向上
{
this.hero.setDirect(0);
this.hero.moveUp();
}
else if(e.getKeyCode() == KeyEvent.VK_D)//向右
{
this.hero.setDirect(1);
this.hero.moveRight();
}
else if(e.getKeyCode() == KeyEvent.VK_S)//向下
{
this.hero.setDirect(2);
this.hero.moveDown();
}
else if(e.getKeyCode() == KeyEvent.VK_A)//向左
{
this.hero.setDirect(3);
this.hero.moveLeft();
}
this.repaint();//调用repaint()函数,来重绘页面
}
}
本篇看来篇幅长了点,实则内容不多,旨在详细描述步骤,下节继续分解