<来自cnmm22:http://blog.csdn.net/cnmm22/article/details/44747783>
我是怎样完成了里世界,分身。
我之前已经完成了夜撩,大阳气炮,夜撩断魂,中华宝轮……后来证明,要实现是世界,分身是一件相当困难的事情,这几乎花了我两天的时间。
我前后想过很多办法,实现的结果不是很理想:
最开始,我想得很简单,就是记录一个时间差,比如只需要记住主角3秒钟前的坐标和攻击方位就行。
后来证明,这种想法太过幼稚。
不过是在实践中才得出这个结论,我这样做了,首先,我建了一个分身类,继承了我自己,省略了若干的方法,只留一个主干,其中包括绘制方法。接下来,我用几个常量记录3秒钟前的坐标和攻击方位,后来的结果是,分身几乎无法移动,即使移动也是瞬间移动。
所以,我想到了,用一个数组,因为我意识到,要顺滑的表现出分身的移动,分身其实就是重复我的移动,那实际上需要记录的是一系列数据,比如他是重复我3秒前的移动,那我不应该只记录3秒前我的状态,而必须记录我在3秒钟里几乎所有状态!
OK,现在开始做,我做了如下改进:我用一个二维数组,比如a[][],第一个下标代表3秒内的每一帧,第二个下标取值为0-2,记录3个数据,x坐标,
y坐标,攻击方向。那从现在(假设已经是3秒后往前推,a[0][0]就带表3秒前第一帧的x坐标,a[100][2]代表大概1秒前的攻击方向。
我把这些数据传递给我的分身,我在分身里定义了相应的3个静态常量,之所以要静态的,是为了方便赋值,因为这些常量我只需要一份,因为同一个分身不可能有多个实例。这时,我想到的是我做一个分身就行了,所以,比如x,y坐标和攻击方向,我只需要一份(当然你也看到了,实际上我做出了多个分身的效果)。
但是,现在问题来了,主要问题有两个:
1、 攻击方向我是定义的一个枚举常量,数组中无法同时传递int 和枚举数据;
2、 最关键的,数组的大小是固定的,我该要定义多大的数组?我也许试过a[10000][3],很显然,我需要分身战斗200秒,每秒假设绘制50帧,那数组可能越界,而且这样会很耗内存,因为内存得不到释放。
所以我必须改变,要同时解决上面两个问题,我思考后,改进为:
我先定义了一个内部类(他们就是最后我完成的方式了,现在我可以粘贴一些代码了):
class Date {
int dx;
int dy;
Directionddir;
public Date(int dx, int dy,
Direction ddir) {
this.dx = dx;
this.dy = dy;
this.ddir = ddir;
}
}
短短几行,却包含了足够信息。
完后,该是一个集合来盛放这些Date对象了,当然LIST和内部类简直是完美的搭配。代码如下:
List<Date> s;
我曾今考虑过这里用一个链表来装这个集合,因为这里不涉及到很多的随机读取,不过考虑到实际实现他后,list 的长度也只有不到20(通常情况下永远不会超过30,后面我会讲实现),所以我只是用了一个ArrayList轻松搞定。
在按下分身键后,一系列的计算开始了:(这就是说不按分身时是不需要去计算和保存list滴)
if (dir !=
Direction.stop) { //如果我在移动,才放入我的状态Date
if (fs1 >
0) { //fs1代表我随机出几个分身,最多4个,我不想要再多了
// if(ap)
a++; //a和b决定了分身跟我的位置。
Dated = new Date(x, y, dir);
//每一次,只要我在移动,记录我的状态到一个Date里,很重要的,必须要移动才记录,否则结果会很尴尬,这是我试出来的,同时这个也保证list 的 size不会太大。
if (s == null)
//因为按下分身后,是一个TimerTask 在记录分身时间,到时则要清理相关的a,b,s等所有信息,释放内存资源,并避免下一次激活分身冲突。
s = newArrayList<Date>();
if (Unit.Dfs)
{ //工具类,如果为真打印调试信息,毕竟项目有些大了。
System.out.println(b + "
a= "+ a + "
" + ",g24.size= "+ t.g24.size()
+ " " + ",s.size= "+ s.size());
}
s.add(d);
if (fs1 ==
1) { //如果有一个分身,至少有一个。
if (a > b)
{//a和b决定了分身跟我的位置。b是每一次timer.cancel时计算的随机值,以供下次激活分身使用。a是每帧自增长而b 是固定不变,比如当b 为17,这个算式代表了,a 将会在17帧后执行下面得操作。
// ap=false;
Funk24.x = s.get(0).dx;
//Funk24为分身类
Funk24.y = s.get(0).dy;
Funk24.dir = s.get(0).ddir;
s.remove(0); //非常关键的,由s.remove(0)和s.get(0).dx;组合成了一个记录,实现机器,并且保证了整个list的大小不会超过b 的大小。
}
}
if (fs1 ==
2) {//如果有2个分身,第一个的出现是必然的,但第二个可能有3种情况,这里是因为我设计了4个不同的分身,而且为他们每一个都设计了单独的类,这是我塑造分身性格的一部分,在我的游戏里,分身是具备不同性格的,也有一些随机性。
if (a > b +
Unit.UF1) { // Unit.UF1这里等于5,实际上代表了2个分身之间的距离,当然也可以是随机数,我这里用到工具类,可以方便的进行修改。
Funk24.x = s.get(Unit.UF1).dx;
Funk24.y = s.get(Unit.UF1).dy;
Funk24.dir = s.get(Unit.UF1).ddir;
s.remove(0); //非常重要的,一定要在list最大的哪种if情形下remove(0),其他情形不用 remove。
}
if (a > b)
{// Funk241- Funk243 和Funk24是所有的4个分身类
if (Funk241.g241 ==
1) {// Funk241.g241 == 1就是说Funk241 被实例化了
Funk241.x = s.get(0).dx;
Funk241.y = s.get(0).dy;
Funk241.dir = s.get(0).ddir;
}
if (Funk242.g242 ==
1) {
Funk242.x = s.get(0).dx;
Funk242.y = s.get(0).dy;
Funk242.dir = s.get(0).ddir;
}
if (Funk243.g243 ==
1) {
Funk243.x = s.get(0).dx;
Funk243.y = s.get(0).dy;
Funk243.dir = s.get(0).ddir;
}
}
}
if (fs1 ==
3) {//如果有3个分身,组合的可能最多,最复杂,但实际也不复杂,有规律
if (a > b +
Unit.UF2) {// Unit.UF2同理是第三个跟第一个的距离
Funk24.x = s.get(Unit.UF2).dx;
Funk24.y = s.get(Unit.UF2).dy;
Funk24.dir = s.get(Unit.UF2).ddir;
s.remove(0); // b +
Unit.UF2无疑是list最大情形,所以在这里s.remove(0).
}
if (Funk241.g241 ==
1 && Funk242.g242 == 1) {// Funk241.g241 ==
1就是说Funk241 被实例化了
if (a > b +
Unit.UF1) {
Funk241.x = s.get(Unit.UF1).dx;
Funk241.y = s.get(Unit.UF1).dy;
Funk241.dir = s.get(Unit.UF1).ddir;
}
if (a > b)
{
Funk242.x = s.get(0).dx;
Funk242.y = s.get(0).dy;
Funk242.dir = s.get(0).ddir;
}
}
if (Funk241.g241 ==
1 && Funk243.g243 == 1) {
if (a > b +
Unit.UF1) {
Funk241.x = s.get(Unit.UF1).dx;
Funk241.y = s.get(Unit.UF1).dy;
Funk241.dir = s.get(Unit.UF1).ddir;
}
if (a > b)
{
Funk243.x = s.get(0).dx;
Funk243.y = s.get(0).dy;
Funk243.dir = s.get(0).ddir;
}
}
if (Funk243.g243 ==
1 && Funk242.g242 == 1) {
if (a > b +
Unit.UF1) {
Funk242.x = s.get(Unit.UF1).dx;
Funk242.y = s.get(Unit.UF1).dy;
Funk242.dir = s.get(Unit.UF1).ddir;
}
if (a > b)
{
Funk243.x = s.get(0).dx;
Funk243.y = s.get(0).dy;
Funk243.dir = s.get(0).ddir;
}
}
}
if (fs1 ==
4) {//如有4个分身,Unit.UF3是第4个跟第一个的距离,这种情形很简单,同时也可以很清楚的看出整个计算流程。
if (a > b +
Unit.UF3) {
Funk24.x = s.get(Unit.UF3).dx;
Funk24.y = s.get(Unit.UF3).dy;
Funk24.dir = s.get(Unit.UF3).ddir;
s.remove(0);
}
if (a > b +
Unit.UF2) {
Funk241.x = s.get(Unit.UF2).dx;
Funk241.y = s.get(Unit.UF2).dy;
Funk241.dir = s.get(Unit.UF2).ddir;
}
if (a > b +
Unit.UF1) {
Funk242.x = s.get(Unit.UF1).dx;
Funk242.y = s.get(Unit.UF1).dy;
Funk242.dir = s.get(Unit.UF1).ddir;
}
if (a > b)
{
Funk243.x = s.get(0).dx;
Funk243.y = s.get(0).dy;
Funk243.dir = s.get(0).ddir;
}
}
if (Unit.Ds11)
{
System.out.println(s.size());//s从未超过过30.
}
}
}
以上就是实现分身的主要代码,除开建立类之外也只有他们了,他们并没有增加很多运算复杂程度。最后press分身键时。
case KeyEvent.VK_Q:
if (fss >
0) { // 能放几炮
if (!fs)
{ // 是否已经放出
fs1++; // 一个分身加一
Funk24g = new Funk24(x, y, dir, t,
Unit.color3);
t.g24.add(g);
//分身有专门的队列g24.
fss -= 1;
fs = true;
if (r.nextInt(2)
== 1) { //除了第一个分身,234个分身出现都是有一定几率的。
fs1++;
Funk241g1 = new Funk241(x, y, dir, t,
Unit.color4);
t.g24.add(g1);
}
if (r.nextInt(2)
== 1) {
fs1++;
Funk242g2 = new Funk242(x, y, dir, t,
Unit.color5);
t.g24.add(g2);
}
if (r.nextInt(2)
== 1) {
fs1++;
Funk243g3 = new Funk243(x, y, dir, t,
Unit.color6);
t.g24.add(g3);
}
// timer = new Timer(); 千万不要每次都new
Timer !
timer.schedule(new TimerTask()
{
public void run()
{
if (!FunkD.pas)
{
if (FunkD.restart)
{
t.g24.clear();
s = null;
a = 0;
fs1 = 0;
b = r.nextInt(17);
cancel();
System.out.println("1========================");
}
fse++; // 计时
if (fse ==
10) {
fs = false;
fse = 0;
if (t.g24.size()
> 0) {
t.g24.clear();
}
s = null;
a = 0;
fs1 = 0;
b = r.nextInt(17);
cancel();
System.out.println("1========================");
}
}
}
},0, 1000); // 40秒等待
}
}
break;
最后,我正在尝试不使用任何开发包,不使用任何工具,用最原始的java代码来开发一个游戏。那是一个很火爆的游戏:
。