照着视频写完坦克大战后想上手超级玛丽了
首先说明,这个只是小白用来练手的,参照的是(马士兵老师的坦克大战视频),因为觉得和有用,就想自己写着玩玩.并且是第一次使用博客.还是有点蒙的
- 第一次使用博客,记录下自己创造的过程
第一部分,创建窗体
用的是Frame这个框架?还是叫窗体,不清楚,反正是个类没错,我新建了一个类,名字叫做GameFrame, 把他继承这个Frame类.就是可以用来画窗体,画小人什么的.
然后在这个类中先确定窗口的大小,我写的是800*600,把它写成静态全局final变量,只需要去用它就可以了.
窗体里面写什么呢? 首先先得搞一个加载窗口的类吧,姑且就叫launchFrame好了,在这个方法里面
我们需要做几件事:
- 设置窗体大小
- 设置窗体名称
- 设置窗体是否可以改变大小
- 设置窗体是否可见!!!
要不然,只能通过STOP来关闭….太难受了.
直接上图看吧
顺序是一致的.
窗体创建好了,但是里面没东西
所以需要我们往里面添加一些小玩意,比如说主角,还有地面!
我们又需要做几件事:
- 创建猪脚类和地图类
- 画出猪脚和地图
- 在窗体类中重写paint方法,吧主角和地图加载到窗体里
很简单的三件事,首先创建主角类:
首先你得有一个坐标,确定猪脚在哪里生成,其次,你需要把猪脚的样子给描绘出来,本来吧,我是想画个小人的,但是呢…请看下图
哇? 这么逼真的吗?? 不不不,其实它张这样
所以我放弃了…主角..你就默默的当个方框吧. 方块还是很好画的,但在画前,记得把画笔的颜色保存下来再进行操作.
地形类一样如此.做好这些之后,我信心慢慢的开始运行,emmm? 怎么什么也没有.原来是没在窗体中把这俩东西画出来.我们使用重写了的paint方法,将这俩给方进去就好了,这里有个神奇的事,你不需要调用paint方法,他会自己调用,所以说了半天,结果是怎么样的?看下图
诶嘿嘿,红色的就是猪脚了,蓝色的是地面? 地面没错了…
光画出来没用,需让他可以动起来
话说先前做坦克大战的时候,坦克是在屏幕上,上下左右的移动,可是我们马里奥同学只会左右走走,最多跳一跳.这个跳就有点意思了
我们不妨想想,跳起来,再落下去怎么落到”地面上”,还有怎么往下落的问题.前者可以设置个碰撞检测,就和坦克大战一样,问题不大,但是让猪脚往下落就是个问题了,我们可以把”跳”设置成往下走,并且设置个参数让它使猪脚一直往下走,但是遇到地面,碰撞检测.这样就可以模拟重力啦!!
首先,添加键盘监听事件
怎么添加呢? 我们是实现keyListener接口呢?还是说继承KeyAdpter类呢? 一般我们可能会尽量不使用继承,而是使用接口,但是,实现keyListener接口需要把这个接口的方法都重写了,但是我们并不需要全部都要.所以我们选择继承KeyAdpter就可以了,选择我们需要重写的方法就好啦.在这里,我们只需要keyPressed()方法和keyReleadsed()方法.顾名思义,就是按键,和抬起按键的方法.然后去加载窗体(launchFrame)中添加监听事件addKeyListener(new KeyMonitor());
然后,去主角类中添加具体的按键
我们需要把keyPressed方法和keyReleased方法写在猪脚类里面.首先我们先确定猪脚的方向,猪脚只会往左往右走,还有跳! 将来还可能会发射子弹… 所以我们需要写4种状态,左,右,下和停止.
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_W:
//起跳高度
y-=40;
break;
case KeyEvent.VK_S:
BD=true;
break;
case KeyEvent.VK_A:
BL=true;
break;
case KeyEvent.VK_D:
BR=true;
break;
}
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
switch (key){
case KeyEvent.VK_S:
BD=false;
break;
case KeyEvent.VK_A:
BL=false;
break;
case KeyEvent.VK_D:
BR=false;
break;
}
}
这里我们可以用枚举 enum Direction{L,R,D,STOP} 这样就可以了,然后设置一个默认状态,就是停止,Direction dir = Direction STOP;
最后添加一个单线程来实现猪脚的运动
我们不妨想想,怎么实现猪脚运动? 其实每次运动都是在屏幕的下一个位置画了一个猪脚,再把前面的猪脚给覆盖掉,这样就实现了猪脚的移动,我们可以定义一个类来实现Runnable接口,
public class PaintThread implements Runnable{
@Override
public void run() {
while (true){
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
每隔50毫秒刷新一次,这样在我们眼里就能看到猪脚移动了.(这里直接复制的坦克大战的)
之后我们需要定义一个方法,让猪脚动起来的方法move(),然后用switch case语句判断当前方向,如果是当前方向,就向当前方向移动. 这样我们的猪脚就动起来了,但是,到现在我们会发现好多问题,比如,猪脚他喵的压根不会动啊,这是因为,没有指定方向啊,我们默认的方向是停止的…无事发生.
所以我们又需要定义一个当前方向的类locateDirection(命名方式是采用坦克大战视频里的,是马士兵老师的哇).里面用简单粗暴的用if else.定义好了之后为下面这样:
private void locateDirection(){
if(BL && !BR && !BD) dir=Direction.L;
else if(!BL && BR && !BD) dir=Direction.R;
else if(!BL && !BR && BD) dir=Direction.D;
else if(!BL && !BR && !BD) dir=Direction.STOP;
}
这样就可以确定猪脚的方向了,我们只需要在按键方法里面使用locateDirection()这个方法就好了,不使用的话你会发现猪脚不是不会动就是沾到地板上了… 说道沾!我们还没有写碰撞检测!!!
让猪脚站到我们画的地图上!
在这了里需要用到碰撞检测.也就需要引入Rectangle这个方法来辅助我们进行碰撞检测了.你问我什么是Rectangle??? 这玩意就是指定坐标空间的一个区域,参数有4个 x,y,with,height. 很简单的.
x,y是坐标,剩下俩是宽和长.我们把猪脚和地图都用这个Rectangle给’包’起来.再借助intersects来判断俩矩形是否交叉就可以做到碰撞检测了!
在猪脚类中添加:
public Rectangle getRect(){
return new Rectangle(x,y,WIDTH,HEIGHT);
}
在地图类中添加:
public Rectangle getRect(){
return new Rectangle(x,y,w,h);
}
所谓地图类,就是和猪脚类一毛一样的…这里都有相同的方法,我爵的可以写一个抽象类,…但是,我们先把基本的做完,理解了大概逻辑再进行这个操作吧. 下面是碰撞逻辑
public boolean collidesWithWall(GameMap g){
if(this.getRect().intersects(g.getRect())){
return true;
}
return false;
}
我们怀着激动的心情运行程序,结果!! 诶?? 怎么没了,,,, 原来猪脚跑到地图下面了… 为啥??因为我们没调用方法啊!!! 然后我们又一次运行,???? 怎么还是没有?? 你原来在骗我..我不干了.~
嘘~ 之所以会这样是因为,我们碰撞逻辑没写完全,再主角和地面碰撞时,什么也没有做,当人就没了啊…怎么办呢? 我们可以再写一个类,用来记录猪脚在Y轴方向上的操作,
private void stay(){
y=oldY;
}
然后在碰撞检测里调用这个方法,当检测到碰撞时,我们把y轴此时的值记录下来,然后覆盖掉猪脚原来的y值,这样猪脚就不会继续往下走了,这也就实现了猪脚真正的站在了地面上.我们来看看猪脚的移动的方法move
void move(){
//贴住地面不至于掉到地底
this.oldY=y;
switch (dir){
case L:
x-=XSpeed;
break;
case R:
x+=XSpeed;
break;
case D:
y+=YSpeed;
break;
case STOP:
break;
}
//假装是重力
y+=20;
}
重力就用简单粗暴的y轴向下就好了.具体的值大家可随意调,
好了,让我们运行起来看看效果!
诶嘿嘿,一个傻傻方块在跳来跳去的….. 大功告成
今天就先这样啦.2018/9/1