游戏开发(三)——WIN32 黑白棋(一)——棋局逻辑的设计

今天以黑白棋为例,开始给一个win32的小游戏设计,

这里打算分3部分介绍

1、棋盘,棋局的现实

2、玩家、AI的现实(且听下回分解)

3、游戏画面的现实(且听下下回分解)

其中第一部分为黑白棋游戏的主要逻辑:

1、棋盘,以及棋盘上的棋子的存储形式。这里用到了位图。

2、是否可以落子的判断(黑白棋是只有你落子的位置,在横竖斜八个方向中任意一个方向,能吃掉对方的子,你才可以落在该位置,八个方向都吃不掉对方子的位置是不能下的),以及吃子的逻辑(吃子的逻辑同样是八个方向,两个己方棋子之间夹住的对方棋子,可以被吃掉,翻转为己方棋子)。这里为了使得代码简介一点,使用了函数指针(不同方向上坐标的变化逻辑不一样)。

3、某一方下了一个子之后,交换手的判断(黑白棋中存在可能,一方下了一个子,并吃掉对方的子,之后对方无子可下,没有一个位置能使得对方能吃掉己方的棋子,所以黑白棋并不一定始终是一人一步来的,它可能存在一方连续落子的情况)。

4、记录玩家每一步下棋的步骤,使得可以悔棋(只悔玩家,不悔AI)。

5、游戏是否结束的判断(由于存在无子可下的情况,有可能双方都无子可以下,即一方将另一方全部吃光,所以黑白棋不一定是下满棋盘才分出胜负)。

第二部分主要为了写AI:

黑白棋的AI其实蛮复杂,有专门的研究黑白棋的AI的算法文章,这里只简单介绍一下,也涉及到几个概念:稳定子、行动力、等,具体在第二部分介绍。

第三部分主要是游戏画面的显示,涉及到windows消息机制,鼠标事件,键盘事件,菜单事件,定时器事件;以及简单的图形、文字绘制,涉及到画笔、画刷填充、绘图层HDC、画线、画圆、显示文字、双缓冲的位图拷贝。

阅读第三部分前,读者可以先行阅读《windows程序设计》一书打个基础。

也可以看完博文之后,再将涉及到的图形API,消息机制等windows程序设计中涉及到的点带回到书中去详细了解。

ps:只看1、3部分,同样可以实现一个黑白棋,只是没有AI,就只能人跟人下

黑白棋游戏在设计中需要注意的几点:

1、惯例,首先要定义好棋盘的坐标,定义为左上角那一格为(0,0),向右为x正方向,向下为y正方向,黑白棋棋盘是一个8*8的棋盘,所以定义两个常量表示:

const int REVERSI_MAX_ROW = 8;
const int REVERSI_MAX_COLUMN = 8;

2、棋盘上棋子的类型分三种:黑子,白子,空白无子,枚举表示

enum EnumReversiPiecesType
{
	enum_ReversiPieces_Null = 0x00,
	enum_ReversiPieces_Black = 0x01,
	enum_ReversiPieces_White = 0x02,
};

这三种情况,其实用2位2进制即可表示,一行8个位置就是16位2进制,就是一个WORD就足够了,所以:

3、棋盘的表示,位图

TArray1<WORD, REVERSI_MAX_ROW> m_Map;

位图是8行,每行是一个WORD,这个TArray1是之前实现的一维数组模板直接用的

4、棋盘上一个位置的设计,因为这里涉及到位置(即坐标)的八方向移动的逻辑,因此将坐标位置单独抽象出来,实现坐标的上下左右以及斜的四方向的坐标变化,然后将其重定义为函数指针,使得后面在坐标变化时,不用switch...case八种情况,而是可以将方向当成参数。

typedef void (ReversiPoint::*ReversiPointForward)();

5、某一方的棋子,在某一坐标位置,向某一方向,是否可以吃掉对方的棋子的判断

bool ReversiCheck(EnumReversiPiecesType type, char row_y, char column_x, ReversiPointForward forward);

是否可以吃子的伪代码:

定义一个坐标对象point,初值为当前点row_y, column_x
记录该方向上的搜索次数search,初值为0
point向forward方向移动
搜索次数search++
while (point是一个合法的坐标,不能移出棋盘外面去了)
{
	取point当前位置的棋子类型
	(此时已经是forward移动一次之后的位置了,不是row_y, column_x了)
	if (当前位置有棋子)
	{
		if (当前位置的棋子类型等于传入参数type,type就是要下的棋子类型)
		{
			if (搜索次数search大于1次)
			{
				说明找到的同色棋子与当前棋子坐标差超过1,point至少移动了2次
				则两子之间夹有不同色的棋子
				符合翻转规则,return true
			}
			else
			{
				说明找到的同色棋子与当前棋子,两子是紧挨着的
				该方向两子之间无子可以翻转
				不符合翻转规则,return false
			}
		}
		else
		{
			说明找到的是不同色的棋子,继续向下一个位置搜
			point向forward方向移动
			搜索次数search++
		}
	}
	else
	{
		一直找到空位也没找到,该方向没有同色棋子,无法翻转
	}
}
超出棋盘范围都没有找到同色棋子,该方向没有同色棋子,无法翻转

6、某一方的棋子,在某一坐标位置,向某一方向,吃掉对方的棋子

void DoReversi(EnumReversiPiecesType type, char row_y, char column_x, ReversiPointForward forward);

伪代码实现

定义一个坐标对象point,初值为当前点row_y, column_x
point向forward方向移动
while (point是一个合法的坐标,不能移出棋盘外面去了)
{
	取point当前位置的棋子类型
	(此时已经是forward移动一次之后的位置了,不是row_y, column_x了)
	if (当前位置的棋子类型不等于传入参数type,type就是下的棋子类型)
	{
		将该位置的棋子类型翻转为type一方的棋子
		point向forward方向移动
		因为在翻转之前做了ReversiCheck的判断
		即这个方向肯定是符合翻转规则,有子可吃的
		所以这里不再判断当前位置的棋子类型是否为空
	}
}

有了上面两个基本函数

7、判断某个位置是否可以落子

bool ReversiCheck(EnumReversiPiecesType type, char row_y, char column_x);

则是分别调用上面的ReversiCheck,然后forward传入不同的方向

8、判断某一方是否可以落子

bool CanPlay(EnumReversiPiecesType type);

即遍历棋盘每一个位置,任意一个位置可以落子,则该方可以落子

9、落一个子之后的吃子

void DoReversi(EnumReversiPiecesType type, char row_y, char column_x);

则是分别调用上面的DoReversi,然后forward传入不同的方向

10、下棋的步骤,为了可以悔棋

typedef struct ReversiStep
{
	ReversiBitBoard m_LastMap;
	EnumReversiPiecesType m_CurrType;

	ReversiStep& operator= (const ReversiStep& temp)
	{
		m_CurrType = temp.m_CurrType;
		m_LastMap = temp.m_LastMap;

		return *this;
	}
}ReversiStep;

这里直接记录落子之前的棋盘状态,以及当前这一步是谁落得子就可以了,悔棋的时候就是恢复棋盘状态到这个人落子之前的状态,然后仍然由该玩家重新落子

落子的时候,填一下ReversiStep,存入链表,悔棋的时候,从链表尾退出一个节点,并将棋盘状态恢复为这个尾节点的状态,即实现了悔棋

一盘棋总共60步下满,这里用了一个对象池,一次性申请好60步所需内存,这样避免在频繁的落子悔棋的过程中,频繁的申请内存

11、最后,判断游戏是否结束的逻辑,即双方都无子可下,则游戏结束

先给个游戏截图吧

下面先贴出第一部分的代码

ReversiCommon.h

#ifndef _ReversiCommon_h_
#define _ReversiCommon_h_

//棋盘大小
const int REVERSI_MAX_ROW = 8;
const int REVERSI_MAX_COLUMN = 8;

enum EnumReversiPiecesType
{
	enum_ReversiPieces_Null = 0x00,
	enum_ReversiPieces_Black = 0x01,
	enum_ReversiPieces_White = 0x02,
};

enum EnumReversiResult
{
	enum_Reversi_Playing = 0,
	enum_Reversi_Draw,
	enum_Reversi_Win_Black,
	enum_Reversi_Win_White,
};

#endif

ReversiPoint.h

#ifndef _ReversiPoint_h_
#define _ReversiPoint_h_

#include "ReversiCommon.h"

typedef struct ReversiPoint
{
	char m_row_y;
	char m_column_x;

	ReversiPoint& operator= (const ReversiPoint& temp)
	{
		m_row_y = temp.m_row_y;
		m_column_x = temp.m_column_x;
		return *this;
	}

	bool operator!= (const ReversiPoint& temp)
	{
		if (m_row_y == temp.m_row_y &&
			m_column_x == temp.m_column_x)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	bool IsValid()
	{
		if (0 <= m_row_y &&
			0 <= m_column_x &&
			m_row_y < REVERSI_MAX_ROW &&
			m_column_x < REVERSI_MAX_COLUMN)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	void UL()
	{
		m_row_y--;
		m_column_x--;
	}

	void U()
	{
		m_row_y--;
	}

	void UR()
	{
		m_row_y--;
		m_column_x++;
	}

	void L()
	{
		m_column_x--;
	}

	void R()
	{
		m_column_x++;
	}

	void DL()
	{
		m_row_y++;
		m_column_x--;
	}

	void D()
	{
		m_row_y++;
	}

	void DR()
	{
		m_row_y++;
		m_column_x++;
	}
}ReversiPoint;

typedef void (ReversiPoint::*ReversiPointForward)();

#endif

ReversiBitBoard.h

#ifndef _ReversiBitBoard_h_
#define _ReversiBitBoard_h_

#include <Windows.h>

#include "TArray.h"

#include "ReversiCommon.h"

class ReversiBitBoard
{
public:
	ReversiBitBoard();
	~ReversiBitBoard();

	ReversiBitBoard& operator= (const ReversiBitBoard& temp);

	void SetPieces(EnumReversiPiecesType type, char row_y, char column_x);

	EnumReversiPiecesType GetPieces(char row_y, char column_x);

	BYTE GetBlackCount();
	BYTE GetWhiteCount();

private:
	TArray1<WORD, REVERSI_MAX_ROW> m_Map;
	BYTE m_BlackCount;
	BYTE m_WhiteCount;
};

#endif

ReversiBitBoard.cpp

#include "ReversiBitBoard.h"

ReversiBitBoard::ReversiBitBoard()
{
	for (int i = 0; i < REVERSI_MAX_ROW; i++)
	{
		m_Map[i] = 0;
	}
	m_BlackCount = 0;
	m_WhiteCount = 0;
}

ReversiBitBoard::~ReversiBitBoard()
{

}

ReversiBitBoard& ReversiBitBoard::operator=(const ReversiBitBoard& temp)
{
	m_Map = temp.m_Map;
	m_BlackCount = temp.m_BlackCount;
	m_WhiteCount = temp.m_WhiteCount;
	return *this;
}

void ReversiBitBoard::SetPieces(EnumReversiPiecesType type, char row_y, char column_x)
{
	WORD oldtype = (m_Map[row_y] & (0x0003 << (column_x * 2))) >> (column_x * 2);
	if (enum_ReversiPieces_Black == oldtype)
	{
		m_BlackCount--;
	}
	else if (enum_ReversiPieces_White == oldtype)
	{
		m_WhiteCount--;
	}

	m_Map[row_y] = m_Map[row_y] & (~(0x0003 << (column_x * 2)));
	m_Map[row_y] = m_Map[row_y] | (type << (column_x * 2));
	if (enum_ReversiPieces_Black == type)
	{
		m_BlackCount++;
	}
	else if (enum_ReversiPieces_White == type)
	{
		m_WhiteCount++;
	}
}

EnumReversiPiecesType ReversiBitBoard::GetPieces(char row_y, char column_x)
{
	WORD value = m_Map[row_y] & (0x0003 << (column_x * 2));
	value = value >> (column_x * 2);
	EnumReversiPiecesType type = static_cast<EnumReversiPiecesType>(value);
	return type;
}

BYTE ReversiBitBoard::GetBlackCount()
{
	return m_BlackCount;
}

BYTE ReversiBitBoard::GetWhiteCount()
{
	return m_WhiteCount;
}

Reversi.h

#ifndef _Reversi_
#define _Reversi_

#include "TBDLinkList.h"
#include "TObjectPool.h"

#include "ReversiCommon.h"
#include "ReversiBitBoard.h"
#include "ReversiPoint.h"

typedef struct ReversiStep
{
	ReversiBitBoard m_LastMap;
	EnumReversiPiecesType m_CurrType;

	ReversiStep& operator= (const ReversiStep& temp)
	{
		m_CurrType = temp.m_CurrType;
		m_LastMap = temp.m_LastMap;

		return *this;
	}
}ReversiStep;

class Reversi
{
public:
	Reversi();
	~Reversi();

	void Init();

	bool CanPlay(EnumReversiPiecesType type);

	bool CanPlay(EnumReversiPiecesType type, char row_y, char column_x);

	void DoReversi(EnumReversiPiecesType type, char row_y, char column_x);

	bool ReversiCheck(EnumReversiPiecesType type, char row_y, char column_x);

	void AddReversiStep();

	void Cancel();

	void SwapPlayer();

	EnumReversiResult IsGameOver();

	EnumReversiPiecesType GetCurrType();

	ReversiBitBoard& GetMap();

private:
	void DoReversi(EnumReversiPiecesType type, char row_y, char column_x,
		ReversiPointForward forward);

	bool ReversiCheck(EnumReversiPiecesType type, char row_y, char column_x,
		ReversiPointForward forward);

	EnumReversiPiecesType m_CurrType;

	ReversiBitBoard m_ReversiMap;

	TBDLinkList<ReversiStep> m_ReversiStepList;
	TObjectPool<TBDLinker<ReversiStep>> m_ReversiStepPool;
};

#endif

Reversi.cpp

#include "Reversi.h"

Reversi::Reversi()
{

}

Reversi::~Reversi()
{

}

void Reversi::Init()
{
	m_CurrType = enum_ReversiPieces_Black;//规定黑先

	m_ReversiStepList.Init(enum_DisableLock);
	m_ReversiStepPool.Init(REVERSI_MAX_ROW * REVERSI_MAX_COLUMN,
		0,
		enum_DisableLock_ObjPool,
		enum_DisableAssign_ObjPool);

	for (int i = 0; i < REVERSI_MAX_ROW; i++)
	{
		for (int j = 0; j < REVERSI_MAX_COLUMN; j++)
		{
			m_ReversiMap.SetPieces(enum_ReversiPieces_Null, i, j);
		}
	}

	m_ReversiMap.SetPieces(enum_ReversiPieces_Black, 3, 3);
	m_ReversiMap.SetPieces(enum_ReversiPieces_White, 3, 4);
	m_ReversiMap.SetPieces(enum_ReversiPieces_White, 4, 3);
	m_ReversiMap.SetPieces(enum_ReversiPieces_Black, 4, 4);
}

bool Reversi::CanPlay(EnumReversiPiecesType type)
{
	for (int i = 0; i < REVERSI_MAX_ROW; i++)
	{
		for (int j = 0; j < REVERSI_MAX_COLUMN; j++)
		{
			if (CanPlay(type, i, j))
			{
				return true;
			}
		}
	}

	return false;
}

bool Reversi::CanPlay(EnumReversiPiecesType type, char row_y, char column_x)
{
	if (enum_ReversiPieces_Null == m_ReversiMap.GetPieces(row_y, column_x))
	{
		if (ReversiCheck(type, row_y, column_x))
		{
			return true;
		}
	}
	return false;
}

bool Reversi::ReversiCheck(EnumReversiPiecesType type,
	char row_y, char column_x)
{
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::UL) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::U) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::UR) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::L) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::R) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::DL) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::D) ||
		ReversiCheck(type, row_y, column_x, &ReversiPoint::DR))
	{
		return true;
	}

	return false;
}

bool Reversi::ReversiCheck(EnumReversiPiecesType type,
	char row_y, char column_x,
	ReversiPointForward forward)
{
	ReversiPoint point = {row_y, column_x};
	EnumReversiPiecesType currType;
	int search = 0;

	(point.*forward)();//向某方向搜寻
	search++;
	while(point.IsValid())
	{
		currType = m_ReversiMap.GetPieces(point.m_row_y, point.m_column_x);
		if (enum_ReversiPieces_Null != currType)
		{
			if (type == currType)
			{
				if (search > 1)
				{
					//找到的同色棋子与当前棋子坐标差超过1,则两子之间夹有不同色的棋子
					return true;
				}
				else
				{
					//否则两子是紧挨着的,该方向两子之间无子可以翻转
					return false;
				}
			}
			else
			{
				//找到的是不同色的棋子,继续
				(point.*forward)();
				search++;
			}
		}
		else
		{
			//一直找到空位也没找到,该方向没有同色棋子,无法翻转
			return false;
		}
	}

	//超出棋盘范围都没有找到同色棋子,该方向没有同色棋子,无法翻转
	return false;
}

void Reversi::DoReversi(EnumReversiPiecesType type,
	char row_y, char column_x)
{
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::UL))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::UL);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::U))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::U);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::UR))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::UR);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::L))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::L);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::R))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::R);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::DL))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::DL);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::D))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::D);
	}
	if (ReversiCheck(type, row_y, column_x, &ReversiPoint::DR))
	{
		DoReversi(type, row_y, column_x, &ReversiPoint::DR);
	}
}

void Reversi::DoReversi(EnumReversiPiecesType type,
	char row_y, char column_x,
	ReversiPointForward forward)
{
	ReversiPoint point = {row_y, column_x};

	(point.*forward)();
	while(point.IsValid())
	{
		if (type != m_ReversiMap.GetPieces(point.m_row_y, point.m_column_x))
		{
			m_ReversiMap.SetPieces(type, point.m_row_y, point.m_column_x);
			(point.*forward)();
		}
		else
		{
			break;
		}
	}
}

void Reversi::AddReversiStep()
{
	TBDLinker<ReversiStep> *pLinker = m_ReversiStepPool.Malloc();
	if (NULL != pLinker)
	{
		pLinker->m_Value.m_LastMap = m_ReversiMap;
		pLinker->m_Value.m_CurrType = m_CurrType;

		pLinker->m_pLinkList = NULL;

		m_ReversiStepList.PushTail(pLinker);
	}
}

void Reversi::Cancel()
{
	TBDLinker<ReversiStep> *pLinker = m_ReversiStepList.PopTail();
	if (NULL != pLinker)
	{
		m_ReversiMap = pLinker->m_Value.m_LastMap;
		m_CurrType = pLinker->m_Value.m_CurrType;

		m_ReversiStepPool.Free(pLinker);
	}
}

void Reversi::SwapPlayer()
{
	EnumReversiPiecesType nexttype;
	if (enum_ReversiPieces_Black == m_CurrType)
	{
		nexttype = enum_ReversiPieces_White;
	}
	else
	{
		nexttype = enum_ReversiPieces_Black;
	}
	if (CanPlay(nexttype))
	{
		m_CurrType = nexttype;
	}
}

EnumReversiResult Reversi::IsGameOver()
{
	if (!CanPlay(enum_ReversiPieces_Black) && !CanPlay(enum_ReversiPieces_White))
	{
		BYTE black = m_ReversiMap.GetBlackCount();
		BYTE white = m_ReversiMap.GetWhiteCount();

		if (black > white)
		{
			return enum_Reversi_Win_Black;
		}
		else if (black < white)
		{
			return enum_Reversi_Win_White;
		}
		else
		{
			return enum_Reversi_Draw;
		}
	}
	else
	{
		return enum_Reversi_Playing;
	}
}

EnumReversiPiecesType Reversi::GetCurrType()
{
	return m_CurrType;
}

ReversiBitBoard& Reversi::GetMap()
{
	return m_ReversiMap;
}

游戏开发(三)——WIN32 黑白棋(一)——棋局逻辑的设计

时间: 2024-08-09 08:29:40

游戏开发(三)——WIN32 黑白棋(一)——棋局逻辑的设计的相关文章

游戏开发(三)——WIN32 黑白棋(三)——游戏画面的现实

整个游戏分3部分介绍. 1.棋局的现实 2.AI的现实 3.游戏画面的现实 提供一下完整项目下载 这是第三部分:画面的显示 这部分其实就比较简单的,说白了就是api的堆砌. 主要了解下windows的消息机制,以及怎么画图 主要是分别封装了下对棋盘,棋子,以及当前轮到谁,当前比分是多少,就是游戏画面上不同的部分的绘制. void DrawReversiBoard(); void DrawReversiPieces(EnumReversiPiecesType type, int row_y, in

游戏开发(三)——WIN32 黑白棋(二)——AI

今天是第二部分:玩家和AI 玩家主要是实现悔棋的功能 AI主要是搜索.最大最小算法,枝剪算法 1.每一步落子的步骤,为了可以悔棋 typedef struct ReversiStep {     ReversiBitBoard m_LastMap;     ReversiStep& operator= (const ReversiStep& temp)     {         m_LastMap = temp.m_LastMap;         return *this;     }

1、Cocos2dx 3.0游戏开发三找一小块前言

尊重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27094663 前言 Cocos2d-x 是一个通用平面游戏引擎.基于一个相同十分著名的游戏引擎 Cocos2d-iPhone 设计. 它继承了 Cocos2d 系列引擎一贯的特点:使用简单.执行高效.灵活,且功能强大. 与 Cocos2d-iPhone 不同的是.Cocos2d-x 还拥有强大的跨平台能力,仅仅须要编写一次代码. 就能够无缝地部署在

9、Cocos2dx 3.0游戏开发三查找值小工厂方法模式和对象

重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27704153 工厂方法模式 工厂方法是程序设计中一个经典的设计模式.指的是基类中仅仅定义创建对象的接口,将实际的实现推迟到子类中. 在这里.我们将它稍加推广,泛指一切生成并返回一个对象的静态函数. 一个经典的工厂方法如同这样: Sprite* factoryMethod() { Sprite* ret = new Sprite(); //在这里对 r

unity3D游戏开发三之unity编辑器二

转:http://blog.csdn.net/kuloveyouwei/article/details/23020995 下面我们介绍下GameObject,游戏对象/物体,通过游戏对象我们可以创建游戏对象,如灯光.粒子.模型.GUI等. GameObject菜单 通过Create Other,我们可以创建系统自带的一些游戏对象,具体如下: Particle System:创建粒子系统 Camera:创建摄像机 GUI Text:创建GUI文本 GUI Texture:创建GUI贴图 3D Te

unity游戏开发之令人上瘾的6大手游设计’潜规则’

在当今智能手机和平板盛行的时代,这些休闲游戏似乎已经达到人手一款的地步.毫无疑问,开发者将在他们的游戏中加入更多的关键心理元素. 为了发现隐藏在休闲游戏设计背后的潜规则,狗刨学习网与Lumo Developments公司的Steve Stopps.Nic Williams.和Jonathan Evans,以及擅长游戏方面的心理学家西蒙·摩尔进行了访谈. 个性化选项快速获取信息 "制作小游戏的时候,作为开发者,你或多或少都需要把自我抛诸门外,"Williams说. 最好的休闲游戏设计者从

MVC模式在游戏开发的应用

原地址: http://www.cocoachina.com/gamedev/2012/1129/5212.html MVC是三个单词的缩写,分别为:模型(Model).视图(View)和控制Controller).MVC是一个设计模式,它强制性地使应用程序的输入.处理和输出分开,将应用程序分成三个核心部件:模型.视图.控制器.它们各自处理自己的任务,关系如图所示: 模型是数据层,视图是表现层,控制器是逻辑层,也对应于程序运行中的数据输入,数据处理,数据输出基本三步骤.事实上,MVC模式开发也适

JavaFX战旗游戏开发 第七课 回合逻辑(完)

上一节课中,我们讲述了SLG中获取移动范围的算法(获取攻击范围也是同理),相对如自动寻径来说,简单不少.由于个人时间问题,这一节课将会把内容讲完,将这个系列完结,并给出示例下载地址. 项目下载地址:JavaFX战旗类游戏开发示例 注意:该项目为e(fx)clipse项目 在战旗游戏开发中,最基本的回合逻辑就是敌方回合和我方回合.当然,在如今的SLG游戏中,往往是根据我方角色和敌方角色的某些数值计算(例如速度之类的),来排列角色操控的列表,而且某些技能还能中断某个角色的操作,将他往操作列表的后面移

Html5 Egret游戏开发 成语大挑战(八)一般性二级页面处理

在游戏中,我们一般会有各种各样的二级页面,比如游戏暂停界面或者游戏结束界面,这些界面组成了对玩家交互主要手段,在游戏开发中,对于这些界面的coding组织是非常有学问的,如果倒退到十年前,游戏开发的老前辈们一定孜孜不倦的上课如何设计好“易读”“可维护”“逻辑清晰”的界面代码,本人曾深陷其中变得对代码抠抠索索,结果事倍功半,原因是什么?老前辈们的一个项目或一段代码可能是长期维护长期使用的,而现在的高速code和超短的产品生命周期,使得完全不用规划那么好的交互代码,有时候可能过几个月自己的代码都不认