在 https://www.youtube.com/playlist?list=ELp5mgUw5g9EY 上的教学视频学习笔记
主要难点:
1.如何用线程 和 循环 控制游戏的 开始,停止状态
2.如何用循环解决 游戏画面 帧数的渲染和控制
3.一些图形图像,缓冲的类
Image, BufferedImage, BufferStrategy, Canvas
代码如下:
package com.main;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.Random;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable
{
public JFrame jframe;
public final int WIDTH = 400; //界面宽度
public final int HEIGHT = 300; //界面高度
public final int SCALE = 2; //缩放比例
public boolean GAME_RUNNING_STATE = false; //游戏运行状态
public int tick_count = 0; //统计已经运行过的总帧数
private BufferedImage buf_img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); //游戏界面的缓冲区?
private int[] pixels = ( (DataBufferInt)buf_img.getRaster().getDataBuffer() ).getData(); //游戏界面的所有像素?
public Game()
{
jframe = new JFrame();
setMaximumSize(new Dimension( WIDTH*SCALE, HEIGHT*SCALE ));
setMinimumSize(new Dimension( WIDTH,HEIGHT) );
setPreferredSize(new Dimension(WIDTH, HEIGHT));
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);
jframe.setVisible(true);
jframe.setLocationRelativeTo(null);
//布局管理器
jframe.setLayout( new BorderLayout() );
jframe.add(this,BorderLayout.CENTER); //把游戏界面放进这个jrame里面的borderLayout里面
jframe.pack();
}
private synchronized void start()
{
//启动游戏线程
new Thread(this).start(); //即调用run()函数
GAME_RUNNING_STATE = true;
}
private synchronized void stop()
{
GAME_RUNNING_STATE = false;
}
public void run()
{
long old_time_ns = System.nanoTime(); //运行进入到本函数的时间(纳秒级别) 1秒 = 1000 000 000 纳秒(ns)
long old_time_ms = System.currentTimeMillis(); //毫秒级别
double nsPerTick = 1000000000D/60D; //我们希望游戏 每秒60帧,那么每帧为 1000000000/60 纳秒
int ticks = 0; //记录理论上的帧数
int frames = 0; //记录实际渲染的帧数
double ticks_has_gone = 0; //记录当前已经走了多少帧
//开始循环
while( GAME_RUNNING_STATE )
{
long now_time_ns = System.nanoTime(); //得出当前时间
ticks_has_gone += (now_time_ns - old_time_ns) / nsPerTick; // 时间差/每帧所需时间 = 走过的帧数,
old_time_ns = now_time_ns; //现在的时间在下一次循环就是旧时间
boolean shouldRender = false; //是否进行渲染
//用走过的帧数是否>=1来判断 当前时间是否够一帧
if( ticks_has_gone >=1 ) //如果 刚好走够一帧
{
ticks++; //加上一帧
tick(); //每一帧所对应的操作,例如图形渲染等
ticks_has_gone -= 1; //清零,继续用ticks_has_gone来记录是否走满一帧
shouldRender = true;
}
if(shouldRender)
{
render();//渲染
frames++;
}
if( System.currentTimeMillis() - old_time_ms >= 1000 )
{
//每过一秒 就对运行的帧数 做一次统计
old_time_ms += 1000; //更新循环里面的old_timer 供下一次循环使用
System.out.println( frames + " " + ticks);
frames = 0; //清零
ticks = 0; //清零
}
}
}
public void tick()
{
tick_count++;
for(int i=0; i< pixels.length; i++)
{
//更改每一个像素
//pixels[i] = i + tick_count; //没有特别的颜色意义,只是看看渲染有变化效果
pixels[i] = i * tick_count; //不懂图形学 不过好象可以在这里做出很多很炫的渲染效果
//pixels[i] = i * new Random().nextInt();
}
}
public void render()
{
BufferStrategy buf_str = getBufferStrategy();
if( buf_str == null)
{
createBufferStrategy(3); //三层缓冲
return;
}
//渲染
Graphics g = buf_str.getDrawGraphics();
g.setColor( Color.blue );
//g.fillRect(0, 0, getWidth(), getHeight() );
g.drawImage(buf_img, 0, 0, getWidth(), getHeight(), null );
g.drawRect(0, 0, getWidth(), getHeight());
g.dispose();
buf_str.show();
}
public static void main(String[] args) {
new Game().start();
}
}