java写的著名游戏_⽤JAVA可以写出什么样的游戏?
游戏设计
植物⼤战僵⼫中有⼀个⼩游戏关卡,屏幕的正上⽅有⼀个滚轮机,会随机⽣成植物,玩家可以选中植物后⾃由选择草坪来进⾏安放。基于此游戏模式,我将该关卡抽取出来,单独做成了⼀个简易版的植物⼤战僵⼫。游戏的画⾯⼤概如下:
屏幕左侧会⾃动⽣成植物的卡牌,单击选中后可以放置在草坪上。右侧会⾃动⽣成僵⼫,不同的僵⼫移动速度不同,⾎量不同,还有的僵⼫有隐藏奖励,⽐如:全屏僵⼫静⽌、全屏僵⼫死亡等。当时竟然没有做游戏的暂停的功能,导致现在截图的时机很难把控,那这⾥就先说⼀下游戏暂停的功能应该怎么做吧。
最简单的⼀种暂停⽅式是⿏标移出屏幕,游戏暂停。所以这⾥需要引⼊⼀个⿏标事件。publicvoidmouseMoved(MouseEvent e){
// 当游戏处于运⾏状态时
if (status == start) {
// 通过⿏标移动事件的对象获取当前⿏标的位置
int x = e.getX();
int y = e.getY();
// 如果⿏标超出了游戏界⾯简单的java游戏代码
if (x > Game.WIDTH || y > Game.HEIGHT) {
// 将游戏的状态改为暂停状态
status = pause;
}
}
}
当然,这只是⼀个简单的通过监听⿏标的位置来改变游戏状态⽅法。还可以使⽤键盘,当按下某个键时游戏暂停,这样的⽤户体验更好。但原理是⼀样的,这⾥就不展⽰代码了。
游戏对象
⾸先分析⼀下游戏中有哪些对象。各式各样的植物,各式各样的僵⼫,各式各样的⼦弹。那么这⾥就可以抽出三个⽗类,分别是植物、僵⼫、⼦弹。在⾯向对象中,⼦类将继承⽗类所有的属性和⽅法。所以可以将三⼤类中,共有的属性和⽅法抽到各⾃的⽗类中。⽐如僵⼫⽗类:publicabstractclassZombie{
// 僵⼫⽗类
// 僵⼫共有的属性
protectedint width;
protectedint height;
protectedint live;
protectedint x;
protectedint y;
......
/
/ 僵⼫的状态
publicstaticfinalint LIFE =0;
publicstaticfinalint ATTACK =1;
publicstaticfinalint DEAD =2;
protectedint state = LIFE;
/*
* 这⾥补充⼀下为什么⽗类是抽象类,⽐如每个僵⼫都有移动⽅法,
* 但每个僵⼫的移动⽅式是不同,所以该⽅法的⽅法体可能是不同的,
* 抽象⽅法没有⽅法体,在⼦类中再去进⾏重写就可以了,
* 但有抽象⽅法的类必须是抽象类,因此⽗类⼀般都是抽象类
*/
/
/ 移动⽅式
publicabstractvoidstep();
....
}
植物⽗类、⼦弹⽗类就同理可得了。
上⾯说到⼦类共有的⽅法需要抽到⽗类中,那么部分⼦类共有的⽅法该如何处理呢?⽐如,豌⾖射⼿、寒冰射⼿可以发射⼦弹,坚果墙就没有射击的这个⾏为。所以这⾥就需要⽤到接⼝(Interface)。publicinterfaceShoot {
// 射击接⼝ - 将部分⼦类共有的⾏为抽取到接⼝中
// 接⼝中的⽅法默认是public abstract的,规范的编码应该将该字段舍去
publicabstract Bullet[]shoot();
}
到此为⽌,游戏对象的属性、⽅法基本都定义完了,⾄于图⽚的显⽰以及如何将图⽚画出来,只需要使⽤相应的API即可,这⾥就不做描述了。⼯作⼀年回过来看看,这⾥能优化的地⽅还有很多,⽐如对象的⾎量、攻击⼒、移动等都可以统统写⼊到配置⽂件中,这样在做游戏参数的调整时,不需要去修改代码相关的内容,只需要修改配置⽂件⾥⾯的参数即可。
游戏内容
现在我们有了游戏的对象,该开始让对象加⼊到游戏中来,接着让他们动起来,最后还得让他们打起来。⾸先,让对象加⼊到游戏中来我是这么做的,这⾥还是以僵⼫为例:
// ⾸先要有⼀个僵⼫的集合
// 僵⼫集合
private List zombies = new ArrayList();
// 接着定义随机⽣成僵⼫⽅法
public Zombie nextOneZombie() {
Random rand = new Random();
// 控制不同种类僵⼫出现的概率
int type = Int(20);
if(type<5) {
return new Zombie0();
}else if(type<10) {
return new Zombie1();
}else if(type<15) {
return new Zombie2();
}else {
return new Zombie3();
}
}
// 僵⼫⼊场
// 设置进场间隔
/*
* 这⾥补充⼀下为什么要设置进场的间隔
* 因为游戏的运⾏是基于定时器的,
* 每隔⼀段时间定时器就会执⾏⼀次你所加⼊定时器的⽅法,
* 所以这⾥需要设置进场间隔来控制游戏的速度。
*/
int zombieEnterTime =0;
publicvoidzombieEnterAction(){
zombieEnterTime++;
// 对⾃增量zombieEnterTime进⾏取余计算
if(zombieEnterTime%300==0) {
// 满⾜条件就调⽤随机⽣成僵⼫⽅法,并将⽣成的僵⼫加⼊到僵⼫的集合中
zombies.add(nextOneZombie());
}
}
最早时候我⽤的数据结构是数组,但在后续的编码中发现,对僵⼫对象有很多的遍历以及增删操作,数组的增删操作是⼗分⿇烦复杂的,所以我就换成了集合。在⼯作中也⼀样,先思考在编码,选择正确的数据结构往往能起到事半功倍的效果。
植物⼊场的设计,是我当时⾃认为很精妙的⼀个点。先说⼀下当时在编码中发现的问题。⾸先植物⼊场时是在滚轮机上的,滚轮机上的移动就会涉及到追击和停⽌的问题。追击的⽅式当然是追前⼀个植物卡牌,但当第⼀个植物卡牌被选中放置到草地上后,那该如何追击呢?
最开始我的做法是给植物多加⼏个状态来解决这个问题,但是发现状态过多会导致if判断中的条件将⼤⼤增加,并且在尝试后还是没有实现想要的效果,于是我就将植物集合⼀分为⼆,在后⾯的游戏功能设计中,回头过来看才发现将植物集合分为滚轮机上的集合和战场上的集合实在是太精妙了。请听我娓娓道来:// 滚轮机上的植物,状态为stop和wait
private List plants =new ArrayList();
// 战场上的植物,状态为life和move -move为被⿏标选中移动的状态,这⾥设计不合理,会引发后⾯的⼀个BUG
private List plantsLife =new ArrayList();
// 植物在滚轮机上的碰撞判定
publicvoidplantBangAction(){
// 遍历滚轮机上植物集合,从第⼆个开始
for(int i=1;i
// 如果第⼀个植物的y⼤于0,并且是stop状态,则状态改为wait
(0).getY()>0&&(0).isStop()) {
<(0).goWait();
}
// 如果第i个植物y⼩于i-1个植物的y+height,则说明碰到了,改变i的状态为stop if(((i).isStop()||(i).isWait())&&
((i-1).isStop()||(i-1).isWait())&&
<(i).getY()<=(i-1).getY()+(i-1).getHeight()
) {
<(i).goStop();
}
/*
* 如果第i个植物y⼤于于i-1个植物的y+height,则说明还没碰到或者第i-1个
* 植物被移⾛了,改变i的状态为wait,可以继续往上⾛
*/
(i).isStop()&&
<(i).getY()&(i-1).getY()+(i-1).getHeight()) { (i).goWait();
}
}
}
// 检测滚轮机上的植物状态
publicvoidcheckPlantAction1(){
// 迭代器
Iterator it = plants.iterator();
while(it.hasNext()) {
Plant p = it.next();
/*
* 如果滚轮机集合⾥有move或者life状态的植物
* 则添加到战场植物的集合中,并从原数组中删除
*/
/*
* 现在发现把滚轮机上move状态的植物添加到
* 战场上植物集合的最佳操作时间点应该是
* 等植物状态变为life后再添加。
* /
if(p.isMove()||p.isLife()) {
plantsLife.add(p);
}
}
}
当然,滚轮机上的对植物状态判断的代码还是显得⽣涩,也正是⾃⼰想优化这段代码时萌⽣了分享游戏设计过程和游戏代码的念头。那么下⾯就说说,这段代码该如何优化:// 先对状态做下说明
// wait - 植物卡牌在滚轮机上移动状态,因为是等着被⿏标选中,所以取名为wait
// stop - 植物卡牌在滚轮机上停⽌状态,有两种情况,1 - 到顶了 2 - 撞到上⼀个卡牌了
// 开始对以下代码进⾏优化
// 如果第i个植物y⼩于i-1个植物的y+height,则说明碰到了,改变i的状态为stop
// if(((i).isStop()||(i).isWait())&&
// ((i-1).isStop()||(i-1).isWait())&&
// (i).getY()<=(i-1).getY()+(i-1).getHeight()
// ) {
// (i).goStop();
// }
// 优化后的代码是这样的
// 将⼀个复杂的boolean拆成多个if条件
if (!((i).isStop()||(i).isWait()) {
break;
}
if (!((i-1).isStop()||(i-1).isWait())) {
break;
}
if (!((i).getY()<=(i-1).getY()+(i-1).getHeight())) {
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论