游戏架构设计Day1

游戏架构与设计开发Day1

欢迎读者进入简单的游戏架构设计开发。由于本作者也正在经历学习的过程。希望借此机会跟大家分享游戏架构的内容。

本文以介绍简单的游戏:坦克大战、合金弹头为基础。

1.游戏架构的设计

  • 敌人可以自由移动——游戏的自动化
  • 主角可以被控制——键盘监听
  • 子弹的自动出现——监听+自动化
  • 背景移动或者音乐——自动化
游戏架构设计的思考:
  1. 人物主角和NPC数据存储
  2. 图片资源加载
  3. C/S客户端与服务器端
开发者关注:
  1. 易于维护
  2. 易于功能扩展
  3. 容易进行项目分割-分工
提取思想:
  • 界面美观——界面显示
  • 游戏提前加载——自动化控制
  • 数据统一管理——数据模型
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.classGameMainJPanel.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);
	    	}
	    }
	}
}

结果如下展示

游戏框架开发第一天内容大致结束。后续内容我会每天跟进并完成放置于专题上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xiao艾扶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值