多线程小游戏

[size=large][b][align=center]多线程小游戏[/align][/b] [/size] [size=medium]
[align=center] ——泡泡堂练习[/align][/size]
[b][size=medium]项目截图:[/size][/b]

[align=center][img]http://dl.iteye.com/upload/attachment/0075/7133/9abf3db7-8754-3572-8b79-926e6eaa90e1.jpg[/img][/align]

[align=center][img]http://dl.iteye.com/upload/attachment/0075/7135/b9184b53-4941-3445-acc8-4ba96591e25a.jpg[/img][/align]

[align=center][img]http://dl.iteye.com/upload/attachment/0075/7137/514d7af6-edc4-35dc-adab-3be431a3f625.jpg[/img][/align]

这是我运用多线程写的第一个小游戏,当我学会了使用线程,我发现平时所接触过的单机游戏其实都很简单;对于一个游戏来说,游戏的情节和美工对于编程人员来说可能是需要花些时间的,因为我没有这方面的基础,但是对于游戏的功能的实现是完全可以达到的。下面就简单的分享一下这个小游戏的开发吧!通过小游戏的开发来看多线程的应用到底是个怎么回事!

[size=medium][b]一、 项目分析[/b][/size]
a) 游戏的要实现的功能很简单
i. 人物的行走
ii. 泡泡的爆炸
iii. 砖块被爆开
b) 开发的技术支持
i. Java的多线程应用
ii. Swing的框架应用
iii. 监听器
iv. Photoshop处理图片
c) 使用线程的对象(技术难点)
i. 人物需要线程控制
ii. 泡泡的操作需要线程控制(可使用.Jif图片代替动画)
iii. 整个面板刷新需要线程控制
d) 需求
i. 游戏的截图(下面附加了)


[b][size=medium]二、 项目开发流程图[/size][/b]


[align=center][img]http://dl.iteye.com/upload/attachment/0075/7139/0d8df91e-a9db-3194-a855-40b35a02dc1e.gif[/img][/align]

[size=medium][b]三、 具体实现[/b][/size]

a) 游戏地图
游戏地图在这里其实就是游戏的场景,我们先把游戏的场景创建出来,然后再让角色到地图里面去跑,当然这个开发流程不是唯一的,可以自由选择,在这里我们先从地图开始。
玩过泡泡堂的人都应该了解泡泡堂里面的地图有很多种,并且不同的地图会有不同的道具,地形有不一样,地图里的景物也不一样,可见,地图是可以切换的并不是唯一的,因此我们需要为每张地图创建一个类,当我们过关了可以自动切换到下一张地图,也可以自己选择在哪个地图中游戏。
再者,地图中的物品各有自己的属性,有的是可被角色推动,有可被角色穿过去,有可被角色穿踩踏;还有可被泡泡炸掉,有不可被泡泡炸掉的;具体细节具体分析,这里只是举例来说。那么我们先从做一个简单的沙漠地图开始:
我们创建一个面板,设置好基本属性后,然后根据面板的大小创建一个二维数组或队列,这个数组或队列是用来标记整个面板的区域,这个面板最好是一个正方形,那么平分下去每个元素块就是一个个小正方形区域;这样的话,游戏中的显示的物品只要根据数组或队列对设置的值来确定具体的物件,角色也只能在这些小正方形块中动,并且如果遇到不能穿过的物件时,只需要判断数组或队列中设置的值来确定停止及炸开。
那么我们这里来参考一下具体的代码实现:
package paopao;
/**
* 二维地图数组元素块
* *
*/
public class MapArray {
private int x;
private int y;
private int perface;// 物品的状态
// 0表示空地、1表示不可炸毁的物品、2表示可炸毁的物品、3表示可以推动的物体、4木桩、5房子、
// 6木箱、7土块、8泡泡 、9爆炸

public void setX(int x) {
this.x = x;
}

public void setY(int y) {
this.y = y;
}

public void setPerface(int perface) {
this.perface = perface;
}

/*
* 返回单元格左上角x坐标
*/
public int getx() {
return x;
}

/*
* 返回单元格左上角y坐标
*/
public int gety() {
return y;
}

/*
* 返回单元格内物品的状态
*/
public int getpeface() {
return perface;
}
}
这是定义的小正方形元素块,其中x,y记录了在地图中的位置,perface是表示区域块的状态0表示空地、1表示不可炸毁的物品、2表示可炸毁的物品、3表示可以推动的物体、4木桩、5房子、6木箱、7土块、8泡泡 、9爆炸;ArrayList<MapArray> map = new ArrayList<MapArray>();我将整个地图视为一个13*15的二维区域

package paopao;

import java.util.ArrayList;

/**
* 沙漠地图
*
* @author Sean 2012-8-11
*
*/
public class Map_One {
ArrayList<MapArray> map;

/**
* 构造函数,接收二维地图存储队列
*
* @param map
*/
public Map_One(ArrayList<MapArray> map) {
this.map = map;
}

/**
* 设置地图信息
*/
public void setMap() {
/**
* 初始化二维地图 0表示空地 1表示无炸开的障碍 2表示可以炸开的障碍 3表示可以推动的物体
*/
for (int i = 0; i < 13; i++)
for (int j = 0; j < 15; j++) {

MapArray mapelement = new MapArray();
mapelement.setX((522 / 13) * j);
mapelement.setY((604 / 15) * i);
mapelement.setPerface(0);
map.add(mapelement);

}
/**
* 地图上的桩子
*/
MapArray mapelement = map.get(16);
mapelement.setPerface(4);
mapelement = map.get(28);
mapelement.setPerface(4);
mapelement = map.get(166);
mapelement.setPerface(4);
mapelement = map.get(178);
mapelement.setPerface(4);

/**
* 地图上的房子
*/
mapelement = map.get(81);
mapelement.setPerface(5);
mapelement = map.get(82);
mapelement.setPerface(5);
mapelement = map.get(83);
mapelement.setPerface(5);
mapelement = map.get(96);
mapelement.setPerface(5);
mapelement = map.get(97);
mapelement.setPerface(5);
mapelement = map.get(98);
mapelement.setPerface(5);

/**
* 地图上的木箱
*/
for (int i = 0; i < 15 * 13; i++) {
if (i == 16 || i == 28 || i == 166 || i == 178 || i == 47
|| i == 48 || i == 49)
continue;
mapelement = map.get(i);
mapelement.setPerface(6);
}
}

/**
* 返回队列
*/

public ArrayList<MapArray> getMap() {
return map;
}
}

这个类是专门创建地图而用,只需要对队列中的元素设置相应的值,我们就可以创建出一个沙漠地图了。然后将这个队列返回交给面板按照对应的物件绘制在面板上,之后我们游戏过程仅仅需要修改这个队列中的值来操作地图上的物件。
好!说到面板绘制地图和物件,这里我们就要开始使用线程了,因为面板只有一个,它是专门负责绘制地图上的所有东西,这里需要注意了,我刚开始尝试做游戏时,犯了一个很大的错误,之前我做的时候,把每个需要绘制的对象都添加刷新面板的操作,结果显示的时候整个面板刷个没停,不停的闪烁;那么现在我们用一个线程来刷新面板,这样就避免了多线程刷新所带来的麻烦。刷新面板的原理就不多说了,请看具体代码实现。
public void paint(Graphics g) {
super.paint(g);

for (int i = 0; i < rolelist.size(); i++) {
/**
* 背景
*/
g.drawImage(backgroup.getImage(), 0, 0, null);
/**
* 泡泡
*/
for (int j = 0; j < paopaolist.size(); j++) {
ObjectRunThread paopao = paopaolist.get(j);
g.drawImage(paopao.icon.getImage(), (paopao.x / (604 / 15))
* (522 / 13), (paopao.y / (522 / 13)) * (604 / 15),
null);

if (paopao.getName().equals("boo1.png")) {

}
if (paopao.getName().equals("span.png"))
paopaolist.remove(j);// 移除泡泡
}



/**
* 角色
*/
CreatRole role = rolelist.get(i);
g.drawImage(role.look.getImage(), role.x, role.y, null);
/**
* 地图显示
*/

for (int t = 0; t < map.size(); t++) {
MapArray mapelement = map.get(t);
/**
* 木桩
*/
if (mapelement.getpeface() == 4) {
MapArray mapelement1 = map.get(t - 15);
g.drawImage(wood1.getImage(), mapelement1.getx(),
mapelement1.gety() + 17, null);
}
if (mapelement.getpeface() == 6) {
MapArray mapelement1 = map.get(t);
g.drawImage(wood2.getImage(), mapelement1.getx(),
mapelement1.gety(), null);
}
/**
* 泡泡四周的爆炸
*/
if (mapelement.getpeface() == 9) {
MapArray mapelement1 = map.get(t);
g.drawImage(wood5.getImage(), mapelement1.getx(),
mapelement1.gety(), null);
}
}
g.drawImage(house.getImage(), 233, 120, null);// 房子

MapArray mapelement = map.get(((role.y + 10) / 40) * 15
+ (role.x + 20) / 40);
if (mapelement.getpeface() != 0) {
g.drawImage(role.look.getImage(), role.x, role.y, null);
}

}
}

b) 角色控制
其实这一步最先实现出来,如何让一个对象在面板上走动,可以按照键盘上的方向键来控制动作,这是我们要实现的功能。
很明显这个对象是要通过键盘上的方向键去控制的,那么我们一定要使用到键盘监听器——KeyAdapter抽象类,在这里我只是简单的给大家分析一下这个抽象类的内部构成,具体的代码实例不展示了,KeyAdapter抽象类是实现了KeyListener这个接口,它里面有以下这个方法:
public void keyTyped(KeyEvent e) {}

public void keyPressed(KeyEvent e) {}

public void keyReleased(KeyEvent e) {}
需要注意啦!这三个方法就是用来监听控制角色动作,监听角色的过程中需要注意这些方面:
1、 角色不能穿墙
2、 角色不能直接穿过障碍物
3、 角色只能沿着上、下、左、右的方向行走,不可以斜着走动
4、 角色走动其实就是改变角色的位置,以及角色显示的状态(如角色的背面,正面,侧面,以及行动中的状态——不停的切换动作图片),那么要设置好走动的速度和方向走动的状态
下面还主要看看角色的属性,了解一下角色是一个什么样的对象,请看实例:
package paopao;

import java.util.ArrayList;
import javax.swing.ImageIcon;

/**
* 创建泡泡堂角色线程
*/
public class CreatRole extends Thread {
/**
* 角色的位置
*/
public int x;
public int y;
/**
* 角色运动的增量
*/
public int xx;
public int yy;
int per = 1;
/**
* 地图二维数组
*/
ArrayList<MapArray> map;

/**
* 角色状态控制(是向左、向上、向右、向下)
*/

boolean face_left = false;
boolean face_back = false;
boolean face_front = false;
boolean face_right = false;
/**
* 角色的形象图片
*/
ImageIcon front = new ImageIcon("role/front.png");
ImageIcon front1 = new ImageIcon("role/front1.png");
ImageIcon front2 = new ImageIcon("role/front2.png");
ImageIcon back = new ImageIcon("role/back.png");
ImageIcon back1 = new ImageIcon("role/back1.png");
ImageIcon back2 = new ImageIcon("role/back2.png");
ImageIcon left = new ImageIcon("role/left.png");
ImageIcon left1 = new ImageIcon("role/left1.png");
ImageIcon left2 = new ImageIcon("role/left2.png");
ImageIcon right = new ImageIcon("role/right.png");
ImageIcon right1 = new ImageIcon("role/right1.png");
ImageIcon right2 = new ImageIcon("role/right2.png");
ImageIcon failue = new ImageIcon("role/failure.png");
/**
* 初始化角色图片
*/
public ImageIcon look;

/**
* 构造函数
*
* @param cyclelist
*/
public CreatRole(ArrayList<MapArray> map) {
this.x = 80;
this.y = 100;
this.xx = 0;
this.yy = 0;
this.look = front;
this.map = map;
}

/**
* 重写run方法
*/
public void run() {

while (true) {

/**
* 首先改变角色前进的增量 再改变角色的坐标
*/
setxy();

x += xx;
y += yy;
if (x <= 0 || x >= 560) {
xx = 0;
}

if (y < -10 || y > 460) {
yy = 0;
}

try {
Thread.sleep(3);
} catch (Exception ef) {
ef.printStackTrace();

}
}

}

/**
* 改变x,y的增量
*/
public void setxy() {
MapArray mapelement1 = map.get(((y + 10) / 40) * 15 + (x + 20) / 40);// 向上走
MapArray mapelement2 = map.get(((y + 55) / 40) * 15 + (x + 30) / 40);// 向下走
MapArray mapelement3 = map.get(((y + 30) / 40) * 15 + (x) / 40);// 向左走
MapArray mapelement4 = map.get(((y + 40) / 40) * 15 + (x + 40) / 40);// 向右走
MapArray mapelement = map.get(((y + 30) / 40) * 15 + (x + 30) / 40);// 向上走

if (mapelement.getpeface() == 9) {
look = failue;
xx = 0;
yy = 0;
mapelement.setPerface(9);
} else {
System.out.println(mapelement1.getpeface());
if (face_back) {
look = back;
look = back1;
look = back2;

if (y >= 0
&& (mapelement1.getpeface() == 0 || mapelement1
.getpeface() == 9)) { // 如果超出界面范围就不设置增量
yy = -per;
} else {
yy = 0;
}
xx = 0;

} else if (face_front) {
look = front;
look = front1;
look = front2;
if (y < 460
&& (mapelement2.getpeface() == 0 || mapelement2
.getpeface() == 9)) {
yy = per;
} else {
yy = 0;
}
xx = 0;

} else if (face_left) {

look = left;
look = left1;
look = left2;
if (x >= 0
& (mapelement3.getpeface() == 0 || mapelement3
.getpeface() == 9))
xx = -per;
else {
xx = 0;
}
yy = 0;

} else if (face_right) {
look = right;
look = right1;
look = right2;
if (x < 560
&& (mapelement4.getpeface() == 0 || mapelement4
.getpeface() == 9))
xx = per;
else {
xx = 0;
}
yy = 0;

} else {// 停止
xx = 0;
yy = 0;
}

}
}

}

这是一个角色线程类,这个角色类决定了角色的所有状态,那么监听器只需要来动态的修改这个角色对象的状态值,就可以操作这个对象进行所有的操作了。就这么简单!

c) 制作泡泡爆炸
这个泡泡爆炸就是一个定时线程,当时间经过5秒后,这个泡泡就会爆炸,其实这个线程类是最简单的,但又是最难控制的。简单在于这个泡泡的爆炸只是一个动画,在角色位置生成一个泡泡,这个泡泡就是一个线程,从泡泡的生成到爆炸以及到爆炸对地图周围物件状态的修改,到泡泡的消失,都是由这一个个独立的线程完成。困难也就是刚刚说了这都是一个个独立的线程,那么线程与线程之间想到同步或者相互通信是有些难度,如果在一行中出现多个泡泡相邻时,只要相邻泡泡爆炸就会引起爆炸范围内的泡泡都一起爆炸,那么此时,线程与线程之间就需要有非常紧密的联系,独个的泡泡不仅仅要决定爆炸的时间、爆炸的范围,同时还需要监测相邻是否有爆炸产生,如有则立刻引起同时爆炸,这是泡泡堂游戏的一个亮点,有些高手就很清楚,这种连环泡泡爆炸的威力是惊人的!
下面根据泡泡这样的一些特性,将代码实例展示如下:
package paopao;

import java.util.ArrayList;

import javax.swing.ImageIcon;

/**
* 实现对象动态
*
* @author Administrator 不停的切换对象的图片
*/
public class ObjectRunThread extends Thread {
/**
* 图片数组
*/
ImageIcon[] iconArray = new ImageIcon[11];
ImageIcon icon;// 初始图片

/**
* 二维地图
*/
ArrayList<MapArray> map;

/**
* 泡泡爆炸时间控制
*/
int paopaotime = 5;

int x, y;// 对象的位置

/**
* 构造函数,获取图片
*
* @param icon1
* @param icon2
* @param icon3
* @param icon4
* @param icon5
* @param icon6
* @param icon7
* @param icon8
* @param icon9
*/
public ObjectRunThread(int x, int y, ArrayList<MapArray> map) {
/**
* 泡泡
*/

// ImageIcon icon1 = new ImageIcon("bar/bar1.png");
// ImageIcon icon2 = new ImageIcon("bar/bar2.png");
// ImageIcon icon3 = new ImageIcon("bar/bar3.png");
// ImageIcon icon4 = new ImageIcon("bar/bar4.png");
// ImageIcon icon5 = new ImageIcon("bar/bar5.png");
// ImageIcon icon6 = new ImageIcon("bar/bar6.png");
// ImageIcon icon7 = new ImageIcon("bar/bar7.png");
// ImageIcon icon8 = new ImageIcon("bar/bar8.png");
// ImageIcon icon9 = new ImageIcon("bar/bar9.png");

// this.iconArray[0] = new ImageIcon("bar/bar1.png");
// this.iconArray[1] = new ImageIcon("bar/bar2.png");
// this.iconArray[2] = new ImageIcon("bar/bar3.png");
this.iconArray[3] = new ImageIcon("bar/bar4.png");
this.iconArray[4] = new ImageIcon("bar/bar5.png");
this.iconArray[5] = new ImageIcon("bar/bar6.png");
this.iconArray[6] = new ImageIcon("bar/bar7.png");
this.iconArray[7] = new ImageIcon("bar/bar8.png");
this.iconArray[8] = new ImageIcon("bar/bar9.png");
this.iconArray[9] = new ImageIcon("map/boo1.png");
this.iconArray[10] = new ImageIcon("map/span.png");
this.map = map;

// this.icon = iconArray[0];
this.x = x;
this.y = y;

}

public void run() {
MapArray paopao = map.get((y / 40 ) * 15 + x / 40);//主泡泡
int i = 3;
while (paopaotime-- != 0) {
if(paopao.getpeface()==9) {
paopao.setPerface(0);
break;
}
/**
* 切换图片
*/

if (i == 8)
i = 3; // 切换的速度

icon = iconArray[i++];

try {
Thread.sleep(450);

} catch (Exception e) {
}

}

paopao.setPerface(99); 泡泡无法穿过去
paopao.setPerface(9);
try {
/**
* 泡泡的爆炸处理
*/
if (y / 40 != 0) {//上爆炸
MapArray paopaomap = map.get((y / 40 - 1) * 15 + x / 40);
if (paopaomap.getpeface() == 6 || paopaomap.getpeface() == 0
|| paopaomap.getpeface() == 10) {
paopaomap.setPerface(9);
}
}
if (y / 40 % 12 != 0||y / 40==0) {//下爆炸
MapArray paopaomap = map.get((y / 40 + 1) * 15 + x / 40);
if (paopaomap.getpeface() == 6 || paopaomap.getpeface() == 0
|| paopaomap.getpeface() == 10)
paopaomap.setPerface(9);

}
if (x / 40 != 0) {//左爆炸
MapArray paopaomap = map.get((y / 40) * 15 + x / 40 - 1);
if (paopaomap.getpeface() == 6 || paopaomap.getpeface() == 0
|| paopaomap.getpeface() == 10)
paopaomap.setPerface(9);

}
if (x / 40 % 14 != 0||x / 40==0) {//右爆炸
MapArray paopaomap = map.get((y / 40) * 15 + x / 40 + 1);
if (paopaomap.getpeface() == 6 || paopaomap.getpeface() == 0
|| paopaomap.getpeface() == 10)
paopaomap.setPerface(9);

}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
icon = iconArray[10];
/**
* 泡泡消失
*/
paopao.setPerface(0);//主泡泡消失
if (y / 40 != 0) {
MapArray paopaomap = map.get((y / 40 - 1) * 15 + x / 40);
if (paopaomap.getpeface() == 9 || paopaomap.getpeface() == 10)
paopaomap.setPerface(0);
}
if (y / 40 % 13 != 12||y / 40 ==0) {
MapArray paopaomap = map.get((y / 40 + 1) * 15 + x / 40);
if (paopaomap.getpeface() == 9 || paopaomap.getpeface() == 10)
paopaomap.setPerface(0);

}
if (x / 40 != 0) {
MapArray paopaomap = map.get((y / 40) * 15 + x / 40 - 1);
if (paopaomap.getpeface() == 9 || paopaomap.getpeface() == 10)
paopaomap.setPerface(0);

}
if (x / 40 % 14 != 0||x / 40==0) {
MapArray paopaomap = map.get((y / 40) * 15 + x / 40 + 1);
if (paopaomap.getpeface() == 9 || paopaomap.getpeface() == 10)
paopaomap.setPerface(0);

}
}

}

从代码实例来看,其实在泡泡这个类中,所要处理的还有泡泡的爆炸范围,爆炸有的东西可以炸掉,有的则不可以,例如:墙、建筑物一般是不能被炸掉的。因此泡泡的爆炸是需要通过一些位置的计算来得到完全。用一个队列来存放角色生成的所有泡泡,检测到有一串连续的泡泡时,可能会一起爆炸。

d) 调试
游戏的调试是需要费比较多的时间的,当你调试的时候你就会发现,你总是能找到游戏的不完美,这就促使了你有不继想完善游戏的欲望;这一点我非常有感触,因为自己以前也是一个游戏玩家,如今自己终于可以尝试着自己做一个简单的小游戏,固然想达到更高的期望,这是一件好事情。但有一点需要注意,对于一个游戏开发来说,一个人的力量始终是有限的,一个好的游戏是需要集结大量人的智慧和需要才能得到高质量的作品,所以对于这个小游戏来说,单从时间和功能上来说,真的很普通和简单,但我相信有朝一日我可以参加制作更大更优秀的游戏。这个游戏只是为了实践应用多线程,了解多线程之间的通信,其次就是为了个人的一种娱乐而已。也愿大家能抱着这样一种娱乐的心态来学习!


[size=medium][b]四、 总结[/b][/size]
2003年7月 盛大自主研发的第一款网络游戏《传奇世界》公开测试;同年9月,正式商业化运营。那个时候的我才刚刚进入初中,学习没多久我就成为了一个在班上公认的向全面发展的好学生,写作、体育、美术、音乐、各项知识竞赛都取得过很好的成绩,又在班上担任班干部,又是好几门学科的课代表,自然学习成绩也不错,班主任常常当众夸奖我,鼓励班上的其他同学都向我看齐;那个时候自己的骄傲和虚荣心在不断的增加,因为对于我这样一个从农村出生的孩子来说,在家庭中很少得到亲人的夸奖,然而在学校里我却一下子得到这么多的荣耀,一个方面觉得自己得了一种很大的满足,的确对我的学习带来很大的激励和信心;但另一方面可能就是对我的个性带来很大的改变,我的争竞、追求自我荣宗、骄傲……慢慢的被酝酿出来。
到了2004年,我进入了体育特长生班,这是我至今都无法明白的一次选择,不知道怎么糊里糊涂的就进入了特长生班,除了正常的文化课程之外,我们每天还需要进行大量的体能训练,每天晚上搞到很晚才回家,在体训队我认识了一大帮子的“拽爷”,一个个都是牛高马大的身材,都是擅长各项体育的学生;而我当时只是偶然在体育短跑测试上拿了第一名,就莫名被体育教学部搞到体育特长生班了,那个时候我根本就不知道这条路到底适不适合我,就只知道这个班在中考的时候可以加分,后来才知道这个加分不是那么容易的。哎,就这样在体训队里呆着,呆了半年,和身边的同学都混熟了,每天都听到大家谈到一些东西“法师”、“道士”、“武士”、“攻城”、“打怪”……聊得热火朝天,甚至还有人手舞足蹈的模仿动作,大家听得津津乐道;果不然被影响一段时间后,我也对这个游戏产生了浓烈的兴趣,之后就跟着这帮“哥们”走上了这条不归路;每天的生活变得更加丰富了,体能训练,上课,去网吧玩传奇,一天到搞到晚,也顾不上做作业学习了,为了在这个虚拟世界的荣耀,我把这个属世的学习丢弃了;初二很快就过去了,没想到我的成绩一落千丈,但爸妈也没有多责怪,自己也已经对学习不清醒了,也不知道自己学习是为了什么,但我知道一件事,似乎我在网络游戏中获得的东西比现实世界获取的东西更多;也由此,我的变得更加疯狂了,记得那个初二的暑假两个月,我一半时间是在网吧里渡过的,都是晚上熬通宵,白天回来睡觉,那么长的时间,爸妈却从来没有发现过一次我外出上网的经历;爸妈还是很相信我的为人,他们会觉得我是一个很乖的孩子,在他们的心目中我不会太让他们操心;也正是这些原因,我变得更加无法自拔,想不到在那个时候我还收获了几个至今还很铁的关系,是他们陪我常常奋战在网吧;这几个好友现在都考上大学了,现在我们走到一起常常聊到过去的那些事,还依然能够让我们热血沸腾;在我的生命中他们就好像我的战友,是几个值得我托付生命的朋友。事情的发展还没有结束,有一句话说得不错“出来混的终有一天要还的”。我的结局不用说也可以想到,最后学业荒废了,遭受着严重的打击;不幸的是,爸妈知道了我们的经历,但又一次出乎我的意料,那次爸妈尽然没有处罚我,只是冷冷的叹了口气,那一刻是我人生中最痛悔一次;之后我的事就不说了,总之现在我又站起来了。
曾经对于游戏的痴迷,让我达到了一种忘我的境界;如今来看那些都只不过是浮云,回顾这段不堪回首的历史,不是为了说明什么,而是想重新告诉自己“在哪里跌倒就在哪里爬起来”,曾经在计算机上跌倒,如果我又要在计算机这项工作上兴起,我很爱玩游戏,但现在我更爱运用计算机去创建价值;所以今天当我能够开始学会编写游戏的时候,是我非常快乐的一次体验,从一个游戏玩家到一个游戏的开发者的跨跃这种心情是非常快乐的。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值