总结:
游戏:碧奇公主历险记
设计步骤:1 实现初界面
首先把每个界面的图片给ps下来(除了前面两页之外,把图片p成一个整体会方便很多),然后通过下面代码来实前两个界面:
public class GameFrame extends JFrame{
//主函数方法
public static void main(String args[]){
//由类创建对象
GameFrame gf=new GameFrame();
//对象窗体初始化
gf.initGameFrame();
}
//对象窗体初始化的方法
public void initGameFrame(){
//设置标题和大小
this.setTitle("小游戏");
this.setSize(554,400);
//设置中间面板
JPanel center=new JPanel();
//设置中间面板的大小
center.setPreferredSize(new Dimension(547,377));
//设置中间面板的颜色
center.setBackground(Color.darkGray);
//将中间面板加到窗体上
this.add(center);
//将第一张图片加到窗体上
ImageIcon icon1=new ImageIcon("img/first.png");
JLabel lab=new JLabel(icon1);
center.add(lab);
//关闭程序时退出进程
this.setDefaultCloseOperation(3);
//设置可见
this.setVisible(true);
//添加画布
Graphics g=center.getGraphics();
//创建监听器获取中间面板局部监听
MouseListener mlis=new MouseAdapter(){
public void mouseReleased(MouseEvent e) {
//鼠标获得坐标
int x=e.getX();
int y=e.getY();
//获得第二个界面
if(x>=185&&x<=317&&y>=208&&y<=225){//鼠标点击这块区域时
GameFrame1 gf1=new GameFrame1();
gf1.initGameFrame1();
//将第一个窗体从内存中释放
GameFrame.this.dispose();
}
if(x>=185&&x<=244&&y>=152&&y<=170){//当鼠标点击这块区域时获得另一界面
GameFrame2 gf2=new GameFrame2();
gf2.initGameFrame2();
//将本窗体从内存中释放
GameFrame.this.dispose();
}
}
};
//中间面板添加鼠标监听器
center.addMouseListener(mlis);
}
}
2.实现图片和人物同时分别向左和右移动
具体做法是 :把p好的整体图添加到界面的中心面板上, 因为人物是通过键盘监听器来完成,所以要在键盘
监听器里面通过人物的xc(增量)来给图片传一个变量。实现图片和人物同时移动还比较简单,但是当人物走到
中心面板最右端时,这时图片和人物都要跳变,即人物跳到中心面板的左边,图片 也要 跳一个中心面板的长度,
这个有 一定的难度,具体代码如下:
// 人物类(把人物设置成一个线程)
public void run(){
while(lifes>0){//当人物生命值大于0时
if(direct==-1){//direct 表示人物运动的方向 -1表示向左运动 1表示向右运动 0表示向上运动 2表示不动
xc = -4;//人物向左的增量
x += xc;//x表示人物的坐标
GameFrame2.size +=xc;//定义size是用来当人物走到最右边时图片的跳变
GameFrame2.tux -=xc; //图片的运动
}
if(direct==1){//人物向右运动时
xc = 4;//人物向右的增量
x +=xc;//坐标
GameFrame2.size +=xc;
GameFrame2.tux -=xc;
}
if(direct==0){//人物向上跳时
for(int i=0;i<10;i++){//向上
y-=yc;
}
try{//异常处理
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
for(int i=0;i<10;i++){//向下
y+=yc;
}
}
direct=2; //默认不运动
//主界面上的键盘监听器
KeyListener klis = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
// 得到键盘码
int t = e.getKeyCode();
if (t == KeyEvent.VK_LEFT) {//左键码
if (role.x >= 1) {//当人物向右运动时
role.direct=-1;
}
}
if (t == KeyEvent.VK_UP) {//上键码
role.direct=0;
}
if (t == KeyEvent.VK_RIGHT) {//右键码
role.direct=1;
}
}
};
//人物跳变的方法:当每过一个界面时,人物坐标跳变为0
if (size % 496 == 0) {
role.x = 0;
}
//背景跳变的方法
if(role.x%496==0){//当role.x返回原点时,图片移动一个界面
tux-=496;
}
//贴背景图片
ImageIcon icon1 = new ImageIcon("222.png");
//tux tuy为背景图片左上角的坐标
gr.drawImage(icon1.getImage(), tux, tuy, null);
if (role.xc >=0) {
// 在背景中添加人
gr.drawImage(role.icon.getImage(), role.x, role.y, null);
}
if (role.xc < 0) {
// 在背景中添加人物
gr.drawImage(role.icon2.getImage(), role.x, role.y, null);
}
3.实现人物按着图片上的轨迹运动,这个比较难而且麻烦,因为遍历图片轨迹的每一点,再人物的坐标比较,具体代码如下:
//首先定义一个点类
public class MyPoint {
Point point;//点
boolean isOk =true;//是否可以站立
//调用Point中的方法
//得到图片上的x点的方法
public double getX(){
return point.x;
}
//得到图片上点y的方法
public double getY(){
return point.y;
}
}
//将所有的点保存到队列当中
points.add(mp);
}
}
// 把图片上所有的点保存到队列当中
static ArrayList<MyPoint> points = new ArrayList<MyPoint>();
public GameFrame2() {
role.start();
int y = 257;
// 将路径中的点保存到队列中
for (int i = 0; i < 4878; i++) {
// 把每一点都创建成具体对象
MyPoint mp = new MyPoint();
if (i <= 271) {
//由 Point 类创建对象
Point p = new Point(i, y);
//将Point 类创建的对象赋给图片上的点
mp.point = p;
mp.isOk = true;
} else if (i > 271 && i <= 435) {
if (i % 4 == 0) {
++y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 439 && i <= 641) {
Point p = new Point(i, y = 294);
mp.point = p;
mp.isOk = true;
} else if (i > 641 && i <= 666) {
if (i % 4 == 0) {
--y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 666 && i <= 706) {
if (i % 2 == 0) {
--y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 706 && i <= 748) {
Point p = new Point(i, --y);
mp.point = p;
mp.isOk = true;
} else if (i > 748 && i <= 777) {
if (i % 2 == 0) {
--y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
}
else if (i > 777 && i <= 1236) {
Point p = new Point(i, y = 200);
mp.point = p;
mp.isOk = true;
} else if (i > 1236 && i <= 1314) {
if (i % 2 == 0) {
++y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 1314 && i <= 1380) {
Point p = new Point(i, ++y);
mp.point = p;
mp.isOk = true;
} else if (i > 1380 && i <= 1446) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 1446 && i <= 1465) {
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 1465 && i <= 1499) {
if (i % 4 == 0) {
--y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 1499 && i <= 1528) {
Point p = new Point(i, --y);
mp.point = p;
mp.isOk = true;
} else if (i > 1528 && i <= 1598) {
if (i % 2 == 0) {
--y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 1600 && i <= 1780) {
Point p = new Point(i, y = 200);
mp.point = p;
mp.isOk = true;
} else if (i > 1780 && i <= 1844) {
if (i % 2 == 0) {
++y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 1844 && i <= 1918) {
Point p = new Point(i, ++y);
mp.point = p;
mp.isOk = true;
} else if (i > 1918 && i <= 1987) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 1987 && i <= 2008) {
Point p = new Point(i, y = 296);
mp.point = p;
mp.isOk = true;
} else if (i > 2008 && i <= 2077) {
if (i % 2 == 0) {
--y;
}
Point p = new Point(i, y);
mp.point = p;
mp.isOk = true;
} else if (i > 2077 && i <= 2139) {
Point p = new Point(i, --y);
mp.point = p;
mp.isOk = true;
} else if (i > 2139 && i <= 2403) {
Point p = new Point(i, y = 200);
mp.point = p;
mp.isOk = true;
} else if (i > 2403 && i <= 2598) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 2598 && i <= 2689) {
Point p = new Point(i, y = 255);
mp.point = p;
mp.isOk = true;
} else if (i > 2689 && i <= 2778) {
Point p = new Point(i, y = 190);
mp.point = p;
mp.isOk = true;
} else if (i > 2778 && i <= 2898) {
Point p = new Point(i, y = 127);
mp.point = p;
mp.isOk = true;
} else if (i > 2898 && i <= 3023) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 3023 && i <= 3517) {
Point p = new Point(i, y = 217);
mp.point = p;
mp.isOk = true;
} else if (i > 3517 && i <= 3605) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 3605 && i <= 3788) {
Point p = new Point(i, y = 160);
mp.point = p;
mp.isOk = true;
} else if (i > 3788 && i <= 3869) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 3869 && i <= 3915) {
Point p = new Point(i, y = 177);
mp.point = p;
mp.isOk = true;
} else if (i > 3915 && i <= 3965) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 3965 && i <= 4087) {
Point p = new Point(i, y = 245);
mp.point = p;
mp.isOk = true;
} else if (i > 4087 && i <= 4216) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 4216 && i <= 4401) {
Point p = new Point(i, y = 156);
mp.point = p;
mp.isOk = true;
} else if (i > 4401 && i <= 4484) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 4484 && i <= 4528) {
Point p = new Point(i, y = 173);
mp.point = p;
mp.isOk = true;
} else if (i > 4528 && i <= 4578) {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
} else if (i > 4578 && i <= 4700) {
Point p = new Point(i, y = 243);
mp.point = p;
mp.isOk = true;
} else {
Point p = new Point(i, y = -1);
mp.point = p;
mp.isOk = false;
}
//人物类中的方法
//人物运动的方法
public void Left(){
// 遍历图片队列中所有的点
for (int i = 0; i < GameFrame2.points.size(); i++) {
//得到图片中的每一点
MyPoint mp = GameFrame2.points.get(i);
if(mp.isOk){
//由点得到每点的x,y坐标
px = (int) mp.getX();
py = (int) mp.getY();
//判断人物的坐标:通过在纸上画图得到role.x 和tux及px之间的关系
if (px ==x -GameFrame2.tux +width) {//width为人物的宽度
y = py -height;
break;
}
}else{
y+=yc;
}
}
}
public void Right(){
// 遍历图片队列中所有的点
for (int i = 0; i < GameFrame2.points.size(); i++) {
MyPoint mp = GameFrame2.points.get(i);
if(mp.isOk){
px = (int) mp.getX();
py = (int) mp.getY();
if (px ==x -GameFrame2.tux + width) {
y = py -height;
break;
}
}else{
yc=20;
y+=yc;
}
}
4.人物发射子弹的方法:把子弹定义为一个线程,有类似抛物线的运动,因为人物随时都可以发射子弹,
所以创建一个队列用来装子弹线程,以便可以用来清除,具体代码如下:
public class ZidanThread extends Thread {
// 定义子弹的属性
int x ;
int y ;
// 定义宽度和高度
int width = 15;
int height = 12;
// 子弹增量
int xc = 10;
int yc = 1;
//创建子弹图片图标
ImageIcon icon = new ImageIcon("img/zidan.png");
//注意:调用其他类中变量时尽量不要设置成静态的,而是像这样传入类就行
Role role;
public ZidanThread(Role role){
this.role=role;
if(role.xc>0){
xc=15;
}else{
xc=-15;
}
//子弹的初始时的具体位置
x=role.x+35;
y=role.y+30;
}
// 调用父类的方法
public void run() {
change();
}
public void change() {
while (true) {
//判断子弹的路径:与图片路径的碰撞问题
//类似于抛物线的判断方法
if(y<role.y+role.height){
x += xc;
y += yc;
yc++;
}
else {
x += xc;
yc = -yc;
y += yc;
yc += 1;
}
try {
Thread.sleep(30);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 创建一个队列,用来装子弹
static ArrayList<ZidanThread> zts = new ArrayList<ZidanThread>();
// 空格键的方法
if (t == 32) {
//由子弹类创建子弹对象的构造方法
zt = new ZidanThread(role);
//启动子弹线程
zt.start();
//将发射的子弹放到队列当中
zts.add(zt);
}
5.子弹用过之后要从队列中清除------------最后在讨论
//当子弹使用过之后从队列中清除子弹的方法
public void test(Graphics gr) {
for (int i = 0; i < zts.size(); i++) {
// 从队列中取出
ZidanThread zt = zts.get(i);
//判断子弹清除的方法
if (zt.yc == 0 ||(( null != zt && (yth.x - zt.x <=1)&& (yth.x - zt.x>=0)&& (yth.y - zt.y) <= 10 ))|| ((null != zt&& Math.abs(gth.x - zt.x) <=1&& Math.abs(gth.y - zt.y) <=20))) {
zts.remove(i);
}
//绘制子弹图片在画布上
gr.drawImage(zt.icon.getImage(), zt.x, zt.y, zt.width, zt.height,
null);
}
}
6.用子弹打怪物的方法,具体是当子弹和怪物超过一定距离时要清除子弹和怪物,具体代码如下:
// 遍历乌龟队列,判断子弹有没有打到乌龟
for (int j = 0; j < GameFrame2.yas.size(); j++) {
//取出乌龟线程
YaThread yth = GameFrame2.yas.get(j);
//判断是否和子弹碰到
if ((yth.x - this.x <=1)&&(yth.x - this.x >= 0) && (yth.y - this.y) <= 10) {
//System.out.println("移除了");
//如果碰到就从队列中移除
GameFrame2.yas.remove(j);
}
}
// 创建一个乌龟队列
static ArrayList<YaThread> yas = new ArrayList<YaThread>();
// 创建一个怪物队列
static ArrayList<GuiwuThread> gws = new ArrayList<GuiwuThread>();
//遍历怪物队列,判断子弹有没有打到怪物
for(int i=0;i<GameFrame2.gws.size();i++){
//取出所有的怪物对象
GuiwuThread gth=GameFrame2.gws.get(i);
//如果超过了一定的距离
if (Math.abs((gth.x - this.x))<=1&& Math.abs(gth.y - this.y) <=20) {
//如果碰到就从队列中移除
GameFrame2.gws.remove(i);
}
}
//重绘中的方法
// 遍历怪物队列
for (int k = 0; k < gws.size(); k++) {
//从队列中取出所有的怪物对象
GuiwuThread gth = gws.get(k);
//在画布上画怪物的图片
gr.drawImage(gth.icon.getImage(), gth.x + tux, gth.y, null);
}
//遍历乌龟队列
for (int k = 0; k < yas.size(); k++) {
//从队列中取出所有的乌龟对象
YaThread ya = yas.get(k);
//在画布上绘制乌龟的图片
gr.drawImage(ya.icon.getImage(), ya.x + tux, ya.y, null);
}
感悟:以上是我这次做这个游戏的可以说是全部了,这次做的游戏很菜,但通过这次做游戏发现做游戏并
不神奇,很多功能上的东东都是我们老师以前讲到过的,比如重绘,比如线程、碰撞等问题,但是还有很
多自己不会的,比如组合键的使用,通过这次做游戏,发现自己有好多以前学的东西有些都忘了,可能是
自己理解不够,下的功夫不够,接下来要做的就是加油了,不贪多,把每次课搞懂,熟练。