房子到期了,刚搬家,网还没转过去,回去之后一个人只能看看广告,不想被电视台QJ,于是就在公司赖着蹭网、蹭空调。实在太无聊,刚好昨天和@zhzhxtrrk聊到了移动设备上的游戏开发,据说在国外美刀赚很凶的,于是乎就写个玩玩呗,度过漫漫长夜。。。
说实话不想装sdk,于是就java上了,上网down素材。。。。然后开始动工。
先简单介绍下游戏的原理吧。
一、重写jpanel的print方法,在这个方法里面做的事情:1.画障碍物(顶部的尖刺) 2.画地板队列中的所有地板 3.画人 4.画图血条等提示信息
二、新建一个线程,这个线程不停的循环,在这个线程中做的事情:1.更新地板的位置 2.随即生成新的地板 3.更新地板动画 4.删除已经在窗口外面的地板
每次循环休眠一段时间,每个循环是一个时钟周期,不同的时钟周期做不同的事情(35个时钟周期生成一个地板,7个时钟周期更新一次地板动画)
效果图:
核心代码剖析:
//画顶部的尖刺
for (int i = 0; i < 300 / 15; i++) {
g1.drawImage(chi, 15 * i, 30, null);
}
man.drawMan(g1);
NFloor tempFloor = null;
//画所有地板
for (int i = 0; i < floorList.size(); i++) {
tempFloor = (NFloor) floorList.get(i);
tempFloor.drawFloor(g1);
}
g1.setColor(Color.ORANGE);
g1.setFont(new Font("Courier", Font.BOLD, 20));
g1.drawString("已经:" + man.getFloor() + "层", 10, 60);
g1.drawString("血:", 10, 85);
g1.setColor(Color.RED);
g1.fillRect(40, 75, man.getHealth(), 10);
g1.setColor(Color.YELLOW);
g1.fillRect(40+man.getHealth(), 75, 100-man.getHealth(), 10);
g.drawImage(buffimg, 0, 0, this);
}
在画图方法中不需要关注任何信息,只需要获取需要画图的对象,然后调用对象的画图方法即可。这里图片的尖刺是画出来的,如果能在底部图上把这些直接画上也是可以的。这样做也有好处,我们可以在画布的四周全部布满尖刺,如果碰到尖刺就死亡,这个也是可以的。
地板的生成:地板队列(floorList)小于10的时候(表明同事出现的地板不超过10个),随即生成一个NFloor,X坐标为(int) (Math.random() * (300 - 100))因为画布宽度为300,地板为100,所以我们不能让地板的最右边超出画布,所以就是300-100之间的随机数。请看下图X的取值原理
//生成新地板,35个周期生成一个
if (count % 35 == 0) {
if (floorList.size() < 10) {
num++;
int floor_x = (int) (Math.random() * (300 - 100));
floorList.add(new NFloor(floor_x, 400 + (int) (Math.random() * 3),
(int) (Math.random() * 6), num));
}
count = 0;
}
if(count % 7 == 0){
//更新地板动画
for (NFloor floor : floorList) {
floor.update();
}
}
count++;
//删除地板
for (Iterator<NFloor> it = this.floorList.iterator(); it.hasNext();) {
NFloor floor = (NFloor) it.next();
if (floor.getY() < 40) {
it.remove();
}
}
//重画
repaint();
}else{
//清空数据
floorList.removeAllElements();
count = 0;
num = 0;
man.setHealth(100);
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
新启动的这个线程中会控制时钟周期(每次时钟周期休眠一段时间,这个值可以看效果订),每个时钟都会更新地板的位置,地板位置的计算公式:x坐标不变(地板X轴始终是不变的)y=y-speed(Y轴的坐标会每次以一定的速度减少,看到的效果就是地板在不停的上升)。同时每35个时钟周期会随即生成一个地板。
同时我们会在每个时钟周期判断一个地板是否超过了画布,如果超过了就直接删除掉。
由于画板中有些地板是有动画效果的,所以需要每7个时钟周期更新一下地板的状态,做出动画效果floor.update()这个随后讲地板的时候在介绍
最后会掉一次repaint()把更新完成的数据重新在画布上画出来。
地板类:
//其他类型的图片都在资源文件里面,这里只需要根据不同的style(地板类型)、donghua(地板的动画状态)来获取需要画的图片即可
try {
img = ImageIO
.read(new File(res.get(String.valueOf(style)).get(String.valueOf(donghua))));
} catch (IOException e) {
}
g1.drawImage(img, x, y, null);
}
每次画地板的时候根据地板的不同style(地板类型)、donghua(地板的动画状态)来获取需要画的图片,然后画到画布上。
每次获取不同的动画状态,供上面的方法在获取图片的时候获取不同的图片。
玩家类:
if (!isDie) {
for (int i = 0; i < game.floorList.size(); i++) {
this.isManOnFloor = false; //初始化角色悬空
floor1 = (NFloor) game.floorList.get(i);
//判断角色是否在地板上以及处理
if (x >= floor1.getX() - MAN_WIDTH && x < floor1.getX() + floor1.width
&& y >= floor1.getY() - MAN_HEIGHT
&& y < floor1.getY() - MAN_HEIGHT + floor1.heigth) {
this.isManOnFloor = true;
floor = floor1.getNum();
ySpeed = floor1.getSpeed();
y = floor1.getY() - MAN_HEIGHT;
break;
}
}
//当人物落在地板上时对应的处理
if (isManOnFloor) {
if (floor1 != null) {
switch (floor1.getStyle()) { //判断落在的地板时什么类型,以及相应的处理方式
case 0: //在刺板上,掉血一次
if (!onDingChi) {
health -= 20;
}
onDingChi = true;
break;
case 1: //左移动的板子,用户的速度左
xFloorSpeed = -1;
break;
case 2: //右移动的板子,用户的速度右
xFloorSpeed = 1;
break;
case 3: //石头板子,不做处理
break;
case 4: //跳板,让用户跳一下(板子上升太快,人下落太快,于是乎,出现狂跳现象)
y -= 20;
break;
case 5: //空心板,害人了。。把用户正常往下掉。
y = y + floor1.heigth;
break;
}
}
} else {
//如果不是在板子上,清空板子上的状态
ySpeed = -4;
xFloorSpeed = 0;
onDingChi = false;
}
try {
img = ImageIO.read(new File("Resources/ManStand.PNG"));
} catch (IOException e) {
}
//左右墙的处理
if (x >= 300 - MAN_WIDTH) {
x = 300 - MAN_WIDTH;
}
if (x <= 0) {
x = 0;
}
g.drawImage(img, x = x + xSpeed + xFloorSpeed, y = y - ySpeed, null);
}
}
在画玩家的时候会判断玩家1.是否还活着(没碰壁,血不为0) 2.玩家是否在地板上(在地板上根据不同的地板做出不同的人的坐标和速度的变化) 3.画人(根据坐标和速度来画)
好了到这里一个下100层的游戏已经搞定了。其实很简单,一个游戏就是不同的始终周期改变用户的位置,然后根据不同位置做出不同逻辑的判断。
好了就到这里吧。下次放出一个小的效验码破解的示例
最后附上源码