游戏架构与设计开发Day1
欢迎读者进入简单的游戏架构设计开发。由于本作者也正在经历学习的过程。希望借此机会跟大家分享游戏架构的内容。
本文以介绍简单的游戏:坦克大战、合金弹头为基础。
1.游戏架构的设计
- 敌人可以自由移动——游戏的自动化
- 主角可以被控制——键盘监听
- 子弹的自动出现——监听+自动化
- 背景移动或者音乐——自动化
游戏架构设计的思考:
- 人物主角和NPC数据存储
- 图片资源加载
- C/S客户端与服务器端
开发者关注:
- 易于维护
- 易于功能扩展
- 容易进行项目分割-分工
提取思想:
- 界面美观——界面显示
- 游戏提前加载——自动化控制
- 数据统一管理——数据模型
MVC3层设计模式:
M(model) V(view) C(control)就是3层模式的设计。
- M模型主要存储主角位置(XY位置)的数据,移动方式的行为。
- V模型获取模型数据,自主刷新。
- C模型主要实现自动化和键盘监听。
上图所示的就是游戏架构的基本内容。后续的项目设计就会基于上图进行开发。
2.游戏团队开发
架构完成后,就要进行团队分工合作
2.1 分包-Java开发包(按照功能进行划分)
-
显示包:界面(
com.tedu.show
) -
控制包:线程、监听(
com.tedu.control
) -
模型包:所有元素类(
com.tedu.element
)-元素管理器:管理器、加载器(
com.tedu.element.manager
)工厂模式-元素类
-
配置文件:游戏配置(
com.tedu.text
) -
游戏启动:启动游戏(
com.tedu.game
) -
图片音乐(
image
)
2.2 进行编写
开发总结:
- 编写元素管理器,完成元素管理器的基本功能。即:1.存储所有元素数据(主角、地图、敌人、BOSS等等)的容器;2.单个管理器即单例模式的实现。
- 编写视图层。视图层在于展示出面板的基本功能“最大最小化等等”,面板监听、多线程、设置面板基本属性等等。
- 可以绘制面板内容。
paint方法调用画笔进行基本的画图
- 元素类创建。比如下文中游戏具有坐标、图片等内容
- 视图面板重写,通过加载并通过元素管理器调取加载图片信息。
2.2.1 元素管理器
1.创建枚举类型GameElement
package com.tedu.manager;
public enum GameElement {
PLAY,MAPS,ENEMY,BOSS;
}
2.创建元素管理器ElementManager
的基本功能。
//元素管理器专门用来存储所有的元素,同时提供方法给予视图和控制获取数据
//1.存储所有的元素数据:list(有序)、map、set(无序)集合
//2.管理器是视图和控制访问,那么管理器只有一个。单例模式
public class ElementManager{
//private list<object> listMap;
//private list<object> listplay;
//String作为键,进行匹配所有的元素。play->list<object> listplay
//枚举类型
//list中的元素的泛型 应该是元素基类
//所有元素都可以存放到map集合中,显示模块只需要获取到这个
private Map<String,list<object>> gameElement;
public Map<gameElement,List<ElementObj>> getGameElements(){
return gameElements;
}
//添加元素(由加载器调用)
public void addElement(ElementObj obj,GameElement ge){
List<ElementObj> list = gameElements.get(ge);
list.add(obj);//根据obj为key进行添加存储
}
//根据key返回list集合,取出一定的元素
public list<ElementObj> getElementsByKey(GameElement ge){
return gameElements.get(ge)
}
//分界线:=========================================
//饱汉模式
private static ElementManager EM=null; //引用
//synchronized线程锁:在进行方法执行时,需要确保只有一个线程。否则有可能会创建两个线程
private static synchronized ElementManager getManager(){
if(EM == NULL){
//空值判定
EM = new ElementManager();
}
return EM
}
private ElementManager(){
init();
//私有化构造方法
}
//恶汉实例化对象
/*static{
//类被加载的时候直接执行
EM=new ElementManager();//执行一次
}*/
public void init(){//实例化完成
//hashmap hash散列
gameElement=new HashMap<GameElement,list<ElementObj>>();
//将每一个元素集合都放入到map中
gameElements.put(GameElement.PLAY,new ArrayList<ElementObj>());
gameElements.put(GameElement.MAP,new ArrayList<ElementObj>());
gameElements.put(GameElement.Enemy,new ArrayList<ElementObj>());
gameElements.put(GameElement.BOSS,new ArrayList<ElementObj>());
}
}
- 单例模式:有且只有一个实例
- 恶汉模式-启动就自动加载实例
- 饱汉模式-需要使用的时候才加载实例
编写方式:
- 需要一个静态的的属性(定义一个常量) 单例的应用
- 提供一个静态的方法(返回这个实例) return单例的使用
- 一般为防止其他人自己使用(类是可以实例化),所以会有私有化构造方法
ElementManager em = new ElementManager();
通过创建完init()
初始化后,元素管理器基本上已经完成两个基本的问题。
2.2.2 视图V
1.创建视图窗口
public class GameJFrame extends JFrame{
private JPanel jpanel = null;//正在显示的面板
private KeyListener keylistener = null;//键盘监听
private Thread thead = null;//游戏主线程
private MouseMotionListener mousemotionlistener=null;//鼠标监听
private MouseListener mouselistener = null;
public static int GameX=900; //GAMEX
public static int GameY=600; //GAMEY
public GameJFrame(){
init();
}
public void init(){
this.setSize(GameX,GameY);
this.setTitle("测试游戏-XXX");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置退出并关闭
this.setLocationRelativeTo(null);//居中
}
//布局窗体:可以保存数据并且读档
public void addButton() {
//this.setLayout(manager);//布局格式,添加控件
}
//启动游戏
public void start() {
if(jpanel !=null) {
this.add(jpanel);
}
if(keylistener!=null) {
this.addKeyListener(keylistener);
}
if(thead!=null) {
thead.start();//启动线程
}
//界面刷新
this.setVisible(true);//显示界面
}
/* set注入,通过set方法注入配置文件中读取的数据;将配置文件中的数据赋值为类的属性
* 构造注入,需要配合构造方法
* spring中ioc进行对象的自动生成
* */
public void setJpanel(JPanel jpanel) {
this.jpanel = jpanel;
}
public void setKeylistener(KeyListener keylistener) {
this.keylistener = keylistener;
}
public void setThead(Thread thead) {
this.thead = thead;
}
public void setMousemotionlistener(MouseMotionListener mousemotionlistener) {
this.mousemotionlistener = mousemotionlistener;
}
public void setMouselistener(MouseListener mouselistener) {
this.mouselistener = mouselistener;
}
}
V模型的游戏窗体中,主要实现的功能有:关闭,显示,最大最小化。
-
面板绑定到窗口
-
监听绑定—键盘、鼠标监听
-
游戏主线程启动—意味着游戏进程的开始
-
显示窗体—布局控件
创建步骤:
- 初始化
init
设置窗体的功能。设置标题、窗体大小、退出、显示、最大最小化、居中。 - set方法注入配置文件中并读取数据。
2.创建游戏主界面(比如可以在面板中画画)
package com.tedu.show;
/*
* 游戏的主要面板
* 功能说明:元素的显示,同时进行界面的刷新(多线程)
* 对于JAVA开发而言,首先实现应该是继承或者接口实现
* */
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JPanel;
import com.tedu.manager.ElementManager;
public class GameMainJPanel extends JPanel{
//联动管理器
private ElementManager em;
public GameMainJPanel() {
}
public void init() {
em=ElementManager.getManager();//得到元素管理器对象
}
//用于绘画的 Graphics 画笔
public void paint(Graphics g) {
super.paint(g);
g.setColor(new Color(255,255,0));
g.setFont(new Font("微软雅黑",Font.BOLD,48));
g.drawString("小乌龟", 375, 200);
g.drawString("|", 443, 250);
g.drawString("V", 433, 270);
g.setColor(new Color(20,252,213));
g.fillOval(400, 300, 100, 200);//填充的椭圆
//乌龟上身
g.fillOval(350, 320, 100, 50);
g.fillOval(450, 320, 100, 50);
//乌龟下身
g.fillOval(350, 430, 100, 50);
g.fillOval(450, 430, 100, 50);
//龟头
g.fillOval(438, 275, 25, 50);
}
}
编译结果如下图所示:
后续在游戏启动时,分别调用视图GameJFrame.class
和GameMainJPanel.class
即可。
2.2.3 元素类创建
创建游戏中的元素。下面代码可根据实际情况具体补充。
package com.tedu.element;
import java.awt.Graphics;
import javax.swing.ImageIcon;
/**
* @说明 所有元素的基类。
*
*
*/
public abstract class ElementObj {
private int x;
private int y;
private int w;
private int h;
private ImageIcon icon;
// 还有。。。。 各种必要的状态值,例如:是否生存.
public ElementObj() { //这个构造其实没有作用,只是为继承的时候不报错写的
}
/**
* @说明 带参数的构造方法; 可以由子类传输数据到父类
* @param x 左上角X坐标
* @param y 左上角y坐标
* @param w w宽度
* @param h h高度
* @param icon 图片
*/
public ElementObj(int x, int y, int w, int h, ImageIcon icon) {
super();
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.icon = icon;
}
/**
* @说明 抽象方法,显示元素
* @param g 画笔 用于进行绘画
*/
public abstract void showElement(Graphics g);
/**
* 只要是 VO类 POJO 就要为属性生成 get和set方法
*/
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public int getH() {
return h;
}
public void setH(int h) {
this.h = h;
}
public ImageIcon getIcon() {
return icon;
}
public void setIcon(ImageIcon icon) {
this.icon = icon;
}
}
元素类针对的是基类的加载。通过如上代码的举例可以获取元素的位置信息和icon加载。
2.2.4 视图加载元素
将元素添加至元素管理器进行存储,并且视图层调用元素管理器的数据进行展示。
package com.tedu.show;
/*
* 游戏的主要面板
* 功能说明:元素的显示,同时进行界面的刷新(多线程)
* 对于JAVA开发而言,首先实现应该是继承或者接口实现
* */
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import com.tedu.element.ElementObj;
import com.tedu.element.play;
import com.tedu.manager.ElementManager;
import com.tedu.manager.GameElement;
public class GameMainJPanel extends JPanel{
//联动管理器
private ElementManager em;
public GameMainJPanel() {
init();
//以下代码会换地方进行重写
load();
}
public void load() {
//图片导入
ImageIcon icon = new ImageIcon("image/tank/play1/player1_down.png");
ElementObj obj = new play(100, 100, 50, 50, icon);//实例化对象
//em.getElementsByKey(GameElement.PLAY).add(obj);//将对象放入到元素管理器中
em.addElement(obj, GameElement.PLAY);
}
public void init() {
em=ElementManager.getManager();//得到元素管理器对象
}
//用于绘画的 Graphics 画笔
public void paint(Graphics g) {
super.paint(g);
g.setColor(new Color(255,255,0));
g.setFont(new Font("微软雅黑",Font.BOLD,48));
g.drawString("小乌龟", 375, 200);
g.drawString("|", 443, 250);
g.drawString("V", 433, 270);
g.setColor(new Color(20,252,213));
g.fillOval(400, 300, 100, 200);//填充的椭圆
//乌龟上身
g.fillOval(350, 320, 100, 50);
g.fillOval(450, 320, 100, 50);
//乌龟下身
g.fillOval(350, 430, 100, 50);
g.fillOval(450, 430, 100, 50);
//龟头
g.fillOval(438, 275, 25, 50);
//====================分界线========================
Map<GameElement, List<ElementObj>> all = em.getGameElements();
Set<GameElement> set = all.keySet();
for(GameElement ge:set) {
//迭代器
List<ElementObj> list = all.get(ge);
for(int i=0;i<list.size();i++) {
ElementObj obj = list.get(i);
obj.showElement(g);
}
}
}
}
结果如下展示
游戏框架开发第一天内容大致结束。后续内容我会每天跟进并完成放置于专题上。