Java学习-节点3

第十一天、十二天、十三天

2D游戏开发

基础

这几天一直在完善自己的基于java的简单2D游戏引擎。
由于我也不知道真正的2D游戏引擎都包含哪些模块,只能按照自己的理解和以前的一些经验去编写。
首先,结合之前的线程知识,我们的2D引擎至少需要一个线程,用来逐帧绘图。这里可以使用sleep人为控制每秒帧率为多少,当cpu无法满足时,便时刻不停的计算,不使用sleep。不过该实现有些复杂,于当前程序用处不大,所以在线程中使用固定时间sleep。
结合之前的知识,要把游戏内所有的物体全部绘制到画面上,需要遍历每一个游戏物体,这里可以用到面向对象思想,即构建一个父类GameObject,将其他的对象继承父类的属性,并重写其抽象方法。不过我个人不喜欢面向对象法,事实上,将所有类别的游戏对象按照其基本数据类型可以存储为多个列表,而不是将每一个种对象存入列表,这样做使程序效率更更高,只不过编程时会略增麻烦(当属性和方法足够多时,一般人类的大脑会很难处理)。
现在,我们有了一个绘制图像的线程类,和一个父类GameObject,在父类中定义一个抽象方法,paint,将每一个新生成的游戏对象都存入主游戏对象列表中,绘制线程将遍历这个列表,调取每一个游戏对象的paint方法进行绘制。
但是此时我们的游戏对象还无法移动,我们在GameObject类中为对象加入x,y,speedx,speedy,dspeedx,dspeedy等属性,为对象添加位置坐标,速度,加速度等信息。(注意最好都使用double,不然当增量很小时容易丢失数据信息,我这里额外增加了一对xx,yy属性)。
有了这些属性之后,我们可以在绘制帧时,调用函数来为每一个游戏对象更新这些属性,貌似有一些游戏引擎是这么做的。
不过我选择了新建一个线程类CalThread,使用与绘制线程不同的时间间隔来计算更新这些属性。在该线程中,遍历调用所有可移动游戏对象的move函数来更新位置。
然而这时我们会发现,游戏对象可以移动了,但是它们都是拖着一条尾巴走的,原因是旧的绘制数据没有被擦除。所以需要在每一帧绘制时,额外绘制一个白色的矩形覆盖掉整张地图。

GameObject类

package com.zht0119.ThreadGame;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

public abstract class GameObject implements Const
{
	static final int BOARD=0;
	static final int BALL=1;
	static final int KILLER=2;
	static final int CROSSSTAR=3;
	static final int BLOOD=4;
	static final int GRASS=5;

static TGameProcess tgp;

public int x,y;
public double xx,yy;
public double speedx,speedy;
public double dspeedx,dspeedy;
public double mass=0.01;
public Color color;
boolean canMove=true;
boolean isDraw=true;
public int type=0;

int layerint=1;  //所属的图层数
int listint=0;  //在主游戏空间列表中的位置
int layerListint=0; //在所属图层游戏空间列表中的位置
Pve selfPve=new Pve(0,0);  //当前正面法向量

public abstract void move();
public abstract void paint(Graphics2D g);
public abstract void paintMap(Graphics2D mg);
public abstract void destroy();


public void usuallyDestroy()
{
	for(int i=listint+1;i<tgp.objects.size();++i)
	{
		tgp.objects.get(i).listint--;
	}
	for(int i=layerListint+1;i<tgp.layers.get(layerint).objects.size();++i)
	{
		tgp.layers.get(layerint).objects.get(i).layerListint--;
	}
	tgp.objects.remove(listint);
	tgp.layers.get(layerint).objects.remove(layerListint);
}
public void speed2Pve()
{
	selfPve.xx=speedx;
	selfPve.yy=speedy;
}
public void dspeed2Pve()
{
	selfPve.xx=dspeedx;
	selfPve.yy=dspeedy;
}
public void maxSpeed(double maxSx,double maxSy)
{
	if(Math.abs(speedx)>maxSx)
	{
		speedx=(speedx>0?1:-1)*maxSx;
	}
	if(Math.abs(speedy)>maxSy)
	{
		speedy=(speedy>0?1:-1)*maxSy;
	}
}
}

在GameObject类中

DeawThread类

package com.zht0119.ThreadGame;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Objects;

public class DrawThread extends Thread implements Const
{
	static TGameProcess tgp;
	BufferedImage buffer=new BufferedImage((int)(MAP_X*quality), (int)(MAP_Y*quality), BufferedImage.TYPE_INT_RGB);
	BufferedImage mapBuffer=new BufferedImage((int)(SMALL_MAP_X*quality), (int)(SMALL_MAP_Y*quality), BufferedImage.TYPE_INT_RGB);
	Graphics2D g2d;
	Graphics2D mg2d;
	public void run()
	{
		g2d=(Graphics2D)buffer.getGraphics();
		g2d.scale(quality, quality);
		mg2d=(Graphics2D)mapBuffer.getGraphics();
		mg2d.scale(quality, quality);
		tgp.g.scale(1/quality, 1/quality);
		tgp.mg.scale(1/quality, 1/quality);
		while(true)
		{
			//clear(tgp.g);
			//paintObjects(tgp.g);
			for(int i=0;i<tgp.layers.size();++i)
			{
				Layer tempLayer=tgp.layers.get(i);
				//System.out.println("layer"+i+":"+tgp.layers.get(i).objects.size());
				if(tempLayer.vis==true)
				{
					drawBuffer(tempLayer.objects);
				}
			}
			showBuffer();
			paintMap();
			//((Graphics2D)tgp.g).drawImage(buffer,10,10,null, null);
			try {Thread.sleep(drawTime);}
			catch(InterruptedException e) {}
		}
	}

private void paintObjects(Graphics2D g,ArrayList<GameObject> objects)
{
	for(int i=0;i<objects.size();++i)
	{
		//System.out.println(objects.size());
		if(objects.get(i).isDraw==true)
		{
			(objects.get(i)).paint(g);
		}
	}
}

private void drawBuffer(ArrayList<GameObject> objects)
{
	paintObjects(g2d,objects);
}
private void showBuffer()
{
	tgp.g.drawImage(buffer, 10-tgp.mainCamera.potx,10-tgp.mainCamera.poty,null, null);
}
private void paintMap()
{
	mg2d.setColor(Color.white);
	mg2d.fillRect(0,0,120,110);
	for(int i=0;i<tgp.objects.size();++i)
	{
		tgp.objects.get(i).paintMap(mg2d);
	}
	tgp.mg.drawImage(mapBuffer, 0, 0, null, null);
	tgp.mg.setColor(Color.blue);
	tgp.mg.drawRect((int)(SMALL_MAP_X*((double)tgp.mainCamera.potx/(double)MAP_X)), (int)(SMALL_MAP_Y*((double)tgp.mainCamera.poty/(double)MAP_Y)), (int)(WINDOW_X/MDSX), (int)(WINDOW_Y/MDSY));
}
}

CalThread类

package com.zht0119.ThreadGame;

import java.util.ArrayList;

public class CalThread extends Thread implements Const
{
	static TGameProcess tgp;
	public void run()
	{
		while(true)
		{
			for(int i=0;i<tgp.objects.size();++i)
			{
				if(tgp.objects.get(i).canMove==true)
				{
					(tgp.objects.get(i)).move();
				}
			}
			calStatic();
			try {Thread.sleep(calTime);}catch(Exception e) {}
		}	
	}
	
	

private void growGrass() {
	// TODO Auto-generated method stub
	
}



private void calStatic()
{
	Ball.center();
	Grass.growGrass();
}
}

双缓冲绘图

这些代码是完整代码,出了绘制和移动还有许多功能,例如,双

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值