AP计算机科学A(APcomputer science A)复习备考攻略视频教程
42885 人在学
二.角色绘制开发过程
1.新建一个java项目Chap6_1
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
public class Chap6_1 {
public Chap6_1() {
Frame app = new Frame("GameFrame");
app.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
}
});
app.setLocation(100, 100);
MyPanel drawB = new MyPanel();
app.add(drawB, BorderLayout.CENTER);
app.pack();
app.setVisible(true);
drawB.gameStart();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new Chap6_1();
// TODO code application logic here
}
}
并在练习文件夹中复制images文件夹,在Chap6_1上右击,选择Paste,把images文件夹粘贴到项目文件夹中.如下图:
粘贴好后:
再在项目的src上右击,选择Paste粘贴,将images文件粘贴进src文件夹中:
粘贴好后:
2.建立一个主类Chap6_1(File-new-Class,输入类名Chap5),
我们先温习以前学过的知识,给这个主类写上代码,代码如下:
3.新建一个类MyPanel,(File-new-Class,输入类名MyPanel)
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class MyPanel extends Panel implements Runnable, KeyListener {
public final static int width = 500;
public final static int heigth = 400;
private Image im;
private Graphics dbg;
private Thread gamethread;
private static final int FPS = 50;
public MyPanel() {
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(this);
setBackground(Color.pink);
setPreferredSize(new Dimension(width, heigth));
}
public void gameStart() {
gamethread = new Thread(this);
gamethread.start();
}
public void gamePaint() {
Graphics g;
try {
g = this.getGraphics();
if (g != null && im != null) {
g.drawImage(im, 0, 0, null);
}
g.dispose();
} catch (Exception e) {
}
}
public void gameRender() {
if (im == null) {
im = createImage(width, heigth);
if (im == null) {
} else {
dbg = im.getGraphics();
}
}
//下面画图
dbg.setColor(Color.pink); //设置背景为粉红色
dbg.fillRect(0, 0, width, heigth);//用背景色填充窗体的矩形框,擦除旧图片
Image image = getToolkit().getImage("Images/p1.gif"); //先载入图片
dbg.drawImage(image,100,100,100,131,this);
}
public void gameUpdate() {
}
public void run() {
long t1,t2,dt,sleepTime;
long period=1000/FPS;
t1=System.nanoTime();
while (true) {
gameUpdate();
gameRender();
gamePaint();
t2= System.nanoTime() ;
dt=(t2-t1)/1000000L;
sleepTime = period - dt;
if(sleepTime<=0)
sleepTime=2;
try {
} catch (InterruptedException ex) { }
t1 = System.nanoTime();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == e.VK_RIGHT) {
}
if (keycode == e.VK_LEFT) {
}
}
public void keyReleased(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == e.VK_RIGHT) {
}
if (keycode == e.VK_LEFT) {
}
}
}
根据我们第二周学的画图知识,我们代码用下面的代码画出Images/p1.gif图片:
因此,实际在游戏中,我们很少直接把一个动画gif图片显示在窗体上,这样会造成闪动情况,我们通常采取切割图片的方法。将一个动画切割成几个动作。
4.新建一个类Animation,(File-new-Class,输入类名Animation),
我们在这个类里实现动画,再用MyPanel调用它。
Animation代码如下:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Animation {
private BufferedImage[] Images;
private int numImages;
private boolean ticksStopped;
private boolean isRepeating;
private int animTime;
private int animSpeed;
private int animTotalTime;
private int showTime;
private int imPosition;
public Animation(String fileName,int num,int speed,int totalTime,boolean repeat) {
//单张图产生动画,filename表示图片文件名,speed表示速度,totalTime表示时间,repeat表示是否重复true重复,false不重复
numImages=num;
animSpeed=speed;
animTotalTime=totalTime;
isRepeating=repeat;
animTime=0;
Images=setAnimImagesFromOneFile(fileName,numImages);
imPosition = 0;
ticksStopped = false;
}
public Animation(String prefixfileName,String postfixFileName ,int num,int speed,int totalTime,boolean repeat) {
//多张图产生动画
numImages=num;
animSpeed=speed;
animTotalTime=totalTime;
isRepeating=repeat;
animTime=0;
Images=this.setAnimImagesFromFiles(prefixfileName, postfixFileName, num);
imPosition = 0;
ticksStopped = false;
}
public BufferedImage loadImage(String fnm) {
try {
BufferedImage im = ImageIO.read(getClass().getResource(fnm));
return im;
} catch (IOException e) {
return null;
}
}
public BufferedImage[] setAnimImagesFromOneFile(String fnm, int num) {
//单张图片的读取方法
BufferedImage bim = loadImage(fnm);//读取名为fnm的文件
BufferedImage[] ims = new BufferedImage[num];//定义数组存放num张图
int imWidth = (int) bim.getWidth() / num; //图像的宽度
int imHeight = bim.getHeight(); //图像高度
Graphics g;
//以下将单个文件中的图像分割成num个存放在数组ims
for (int i = 0; i < num; i++) {
ims[i]= new BufferedImage(imWidth,imHeight,BufferedImage.TYPE_INT_ARGB);
g=ims[i].getGraphics();
g.drawImage(bim, 0, 0, imWidth, imHeight, i*imWidth,0,(i*imWidth)+imWidth,imHeight, null);
g.dispose();
}
return ims;
}
public BufferedImage[] setAnimImagesFromFiles(String prefixFileName,String postFileName, int num){
//从一组图片中读取图片放进数组
BufferedImage[] ims = new BufferedImage[num];
for(int i=0;i<num;i++){
ims[i]=loadImage(prefixFileName+String.valueOf(i)+postFileName);
}
return ims;
}
public void updateImage()
/* We assume that this method is called every animPeriod ms */
{
if (!ticksStopped) {
// 更新动画播放时间
animTime = (animTime + animSpeed) % (1000 * animTotalTime);
showTime = (int) (1000 * animTotalTime / numImages);
// 计算动画切换时间
imPosition = (int) (animTime / showTime);
if ((imPosition == numImages-1) && (!isRepeating)) { // 如果指向了图片数组中的最后一张,且不需要动了。
ticksStopped = true; // 停止动画
}
}
}
public BufferedImage getCurrentImage(){
return Images[imPosition];
}
public void stop()
/* updateTick() calls will no longer update the
total animation time or imPosition. */
{ ticksStopped = true; }
public boolean isStopped()
{ return ticksStopped; }
public void resume()
// start at previous image position
{
if (numImages != 0)
ticksStopped = false;
}
public void draw(Graphics g,int x ,int y){
BufferedImage im=Images[imPosition];
g.drawImage(im, x, y, null);
}
}
5.回去改写前面的MyPanel代码如下:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class MyPanel extends Panel implements Runnable, KeyListener {
public final static int width = 500;
public final static int heigth = 400;
private Image im;
private Graphics dbg;
private Thread gamethread;
private static final int FPS = 50;
private Animation myAnimation;//实例化Animation对像
private int x,y;//定义显示的坐标
public MyPanel() {
x=200;//最初显示的x坐标
y=200;//最初显示的y坐标
myAnimation=new Animation("/Images/duck_right.gif", 4,80, 2, true);
//上面,4表示有四张图,80表示播放一组动画的总时间,2表示播放速度,true表示循环播放
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(this);
setBackground(Color.pink);
setPreferredSize(new Dimension(width, heigth));
}
public void gameStart() {
gamethread = new Thread(this);
gamethread.start();
}
public void gamePaint() {
Graphics g;
try {
g = this.getGraphics();
if (g != null && im != null) {
g.drawImage(im, 0, 0, null);
}
g.dispose();
} catch (Exception e) {
}
}
public void gameRender() {
if (im == null) {
im = createImage(width, heigth);
if (im == null) {
} else {
dbg = im.getGraphics();
}
}
//下面画图
dbg.setColor(Color.pink); //设置背景为粉红色
dbg.fillRect(0, 0, width, heigth);//用背景色填充窗体的矩形框,擦除旧图片
myAnimation.draw(dbg, x, y);//调用Animation类中的draw方法,在x,y坐标处显示图片
}
public void gameUpdate() {
myAnimation.updateImage();
}
public void run() {
long t1,t2,dt,sleepTime;
long period=1000/FPS;
t1=System.nanoTime();
while (true) {
gameUpdate();
gameRender();
gamePaint();
t2= System.nanoTime() ;
dt=(t2-t1)/1000000L;
sleepTime = period - dt;
if(sleepTime<=0)
sleepTime=2;
try {
} catch (InterruptedException ex) { }
t1 = System.nanoTime();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == e.VK_RIGHT) {
x++;//按下向右时,x增加
}
if (keycode == e.VK_LEFT) {
x--;//按下向左时,x减少
}
}
public void keyReleased(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == e.VK_RIGHT) {
}
if (keycode == e.VK_LEFT) {
}
}
}
事实上,当我们控制移动时,向左和向右,选用的是不同的图像。所以上面的代码并不完美,我们还需要修改,实现向右显示的是duck_right.gif图片,向左显示的是duck_left.gif图片
6.再修改MyPanel代码如下:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class MyPanel extends Panel implements Runnable, KeyListener {
public final static int width = 500;
public final static int heigth = 400;
private Image im;
private Graphics dbg;
private Thread gamethread;
private static final int FPS = 50;
private Animation myAnimation1,myAnimation2;
private int x,y;//定义显示的坐标
private int d=1;//定义d表示方向,1表示向右,0表示向左
public MyPanel() {
x=200;
y=200;
myAnimation1=new Animation("/Images/duck_right.gif", 4,80, 2, true);
//定义向右的图片
myAnimation2=new Animation("/Images/duck_left.gif", 4,80, 2, true);
//定义向左的图片
//上面,4表示有四张图,80表示播放一组动画的总时间,2表示播放速度,true表示循环播放
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(this);
setBackground(Color.pink);
setPreferredSize(new Dimension(width, heigth));
}
public void gameStart() {
gamethread = new Thread(this);
gamethread.start();
}
public void gamePaint() {
Graphics g;
try {
g = this.getGraphics();
if (g != null && im != null) {
g.drawImage(im, 0, 0, null);
}
g.dispose();
} catch (Exception e) {
}
}
public void gameRender() {
if (im == null) {
im = createImage(width, heigth);
if (im == null) {
} else {
dbg = im.getGraphics();
}
}
//下面画图
dbg.setColor(Color.pink); //设置背景为粉红色
dbg.fillRect(0, 0, width, heigth);//用背景色填充窗体的矩形框,擦除旧图片
if(d==1)
myAnimation1.draw(dbg, x, y);//如果是向右,调用Animation1
if(d==0)
myAnimation2.draw(dbg, x, y);//如果是向左,调用Animation2
}
public void gameUpdate() {
if(d==1)
myAnimation1.updateImage();
if(d==0)
myAnimation2.updateImage();
}
public void run() {
long t1,t2,dt,sleepTime;
long period=1000/FPS;
t1=System.nanoTime();
while (true) {
gameUpdate();
gameRender();
gamePaint();
t2= System.nanoTime() ;
dt=(t2-t1)/1000000L;
sleepTime = period - dt;
if(sleepTime<=0)
sleepTime=2;
try {
} catch (InterruptedException ex) { }
t1 = System.nanoTime();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == e.VK_RIGHT) {
x++;//按下向右时,x增加
d=1;//方向向右
}
if (keycode == e.VK_LEFT) {
x--;//按下向左时,x减少
d=0;//方向向左
}
}
public void keyReleased(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == e.VK_RIGHT) {
}
if (keycode == e.VK_LEFT) {
}
}
}
保存并运行,按向左右的箭头,看一下的移动效果。