【Java 2D游戏开发(三)】渲染线程/让Sprite动起来

效果图:
运行成功!


针对上次的只有更新窗口时画面才会重画,解决方法很简单:
只需要新建一个线程,隔一段时间就通知游戏窗口重画,不停的在窗口上重画,看起来就好像是动态的画面,实质上只是静态的图片

隔多久呢?
一般的2D游戏的帧数在20-30fps左右

什么是帧/FPS:
帧(Frame):画在游戏窗口上的一张静态图
帧速率(FPS/帧数):静态图片更新速度的快慢(FPS = 1秒 / 1秒内渲染的帧数)


首先修改Game类,添加以下代码:

	//.....
	private int fps;//游戏的FPS
	//.....
	
	//.....
	
	/**
	 * 退出游戏
	 */
	public void exit()
	{
		System.exit(1);
	}
	
	/**
	 * 返回游戏的FPS
	 */
	public int getFPS()
	{
		return fps;
	}
	
	/**
	 * 设置游戏的FPS
	 * @param fps 新FPS
	 * @return 是否设置成功
	 */
	public Boolean setFPS(int fps)
	{
		if(fps <= 0)
			return false;
		else 
		{
			this.fps = fps;
			return true;
		}
	}
	//.....

新建类RenderThread,用来定时重画窗口

package com.game.engine;

public class RenderThread implements Runnable
{
	private Thread thread;
	private boolean exited = false;//游戏是否退出
	private int interval;//每次绘制隔多久
	public Game game;
	
	public RenderThread(Game g)
	{
		game = g;
		interval = 1000 / game.getFPS();//计算出隔多久重画一次(毫秒)
		System.out.println("[Render]Created");
		System.out.println("[Render]Render interval: " + interval + " ms");
	}
	
	@Override
	public void run()
	{
		System.out.println(thread.getName() + "Start rendering");
		while (!exited)
		{
			game.repaint();//通知游戏窗口重画
			try
			{
				Thread.sleep(interval);//间隔一定时间渲染一次,来实现稳定fps
			} 
			catch (Exception e)
			{
				System.out.println(thread.getName() + "Error: " + e.toString());
				break;
			}
		}
		System.out.println(thread.getName() + "Stop rendering");
		game.exit();
	}
	
	public void start()
	{
		if(thread == null)
		{
			thread = new Thread(this, "[RenderThread]");
			thread.start();
		}
	}

}

在启动游戏的同时启动渲染线程

	//Game类...
	private RenderThread render;
	//....

	public Game(int windowWidth, int windowHeight, int fps)
	{
		width = windowWidth;
		height = windowHeight;
		this.fps = fps;
		windowTitle = "Game";
		backgroundColor = Color.BLACK;
		
		gameObjects = new ArrayList<GameObject>();
		createWindow();
		render = new RenderThread(this);//初始化线程
		render.start();//启动线程
	}

启动游戏,看看效果:
成功显示出Sprite
可以看到不需要刷新窗口就能显示出来
下面让Sprite动起来,以便更好地观察效果


修改GameObject类,添加onTick方法,这个方法会在游戏渲染每一帧的时候被调用

	/**
	 * 在游戏的每帧被调用
	 */
	public void onTick()
	{
		
	}

下面为了修改让这个方法有实际用途,创建类Player继承Sprite,就可以重写onTick方法:

package com.undertale;

import com.game.engine.GameObject;
import com.game.engine.Sprite;

public class Player extends Sprite
{

	public Player(String filePath)
	{
		super(filePath);
	}
	
	@Override
	public void onTick()
	{
		this.transfer(1, 0);//在当前位置的基础上向右移动1个单位长度
	}

}

修改Main方法:

game = new Game(700, 500, 30);//30fps
Player s = new Player("C:\\Users\\Administrator\\Desktop\\a\\spr_maincharad\\char_forward_0.png");
s.setPosition(50, 50);
game.addGameObject(s);

启动游戏,好像还是没效果?
Sprite静止
因为onTick方法还没有被调用!
修改一下Game类,调用onTick方法

//重写窗体绘制方法
	@Override
	public void paint(Graphics g)
	{
		//渲染所有的sprite
		for(int i = 0; i < gameObjects.size(); i++)
		{
			gameObjects.get(i).onTick();
			gameObjects.get(i).draw(g);
		}
	}

动态效果图
为什么有拖影?因为我们在画第二帧时第一帧画的内容并没有被清除掉,所以会有长长的拖影
在每次渲染时清除上次画的内容即可

	//重写窗体绘制方法
	@Override
	public void paint(Graphics g)
	{
		clear(g);
		
		//渲染所有的sprite
		for(int i = 0; i < gameObjects.size(); i++)
		{
			gameObjects.get(i).onTick();
			gameObjects.get(i).draw(g);
		}
	}
	
	public void clear(Graphics g)
	{
		g.setColor(Color.BLACK);//设置画笔颜色为黑色
		g.fillRect(0, 0, width, height);//填充整个窗口为黑色
	}

再运行一次:
运行成功!
但是出现了闪烁现象,这是下一次要解决的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值