⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mainwin.cpp

📁 源代码演示了在Windows下角色扮演游戏的制作过程
💻 CPP
字号:
//
// Script player主窗口(MainWindow)
//
//		Copyright (c) 2000-2002 Chihiro.SAKAMOTO (HyperWorks)
//
#include "StdAfx.h"
#include "ScrPlay.h"
#include "Window.h"
#include "MainWin.h"
#include "AboutDlg.h"
#include "Misc.h"
#include "dc.h"
#include "resource.h"

// CG的显示位置
const CRect CMainWin::Position[] = {
	CRect(0, 0, 0, 0),												// None
	CRect(0, 0, WindowWidth / 2, WindowHeight),						// Left
	CRect(WindowWidth / 2, 0, WindowWidth, WindowHeight),			// Right
	CRect(0, 0, WindowWidth, WindowHeight),							// Both
	CRect(WindowWidth / 4, 0, WindowWidth * 3 / 4, WindowHeight),	// Center
} ;

//
// 构造函数
//
// 变量的初始化
//	  当窗口由OnCreate初始化时,没有带出任何东西
//
CMainWin::CMainWin():
	TextRect(MSG_X, MSG_Y, MSG_X + MSG_W, MSG_Y + MSG_H),
	WaitMarkRect(MsgX(WAITMARK_X), MsgY(WAITMARK_Y),
		MsgX(WAITMARK_X) + MessageFont, MsgY(WAITMARK_Y) + MessageFont),
	InvalidRect(0, 0, 0, 0)
{
	CurX = CurY = 0;
	OverlapFlags = 0;
	BgColor = BlackPixel;
	TextDisplay = FALSE;
	WaitMarkShowing = FALSE;

	OverlapBounds.SetRectEmpty();
	BackShow = FALSE;
	OverlapShow = FALSE;
	TextShow = FALSE;
	MenuShow = FALSE;

	Action = &NopAction;
	hFont = 0;
}

//
// 析构函数
//
CMainWin::~CMainWin()
{
	if (hFont) {
		DeleteObject(hFont);
		hFont = 0;
	}
}

//
// 窗口制作的前置处理
//
// 指定样式与大小
//
BOOL CMainWin::PreCreateWindow(CREATESTRUCT &cs)
{
	cs.dwExStyle = WS_EX_CLIENTEDGE;
	cs.style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

	CRect	rect(0, 0, WindowWidth, WindowHeight);
	::AdjustWindowRectEx(&rect, cs.style, TRUE, cs.dwExStyle);

	int width = rect.Width();
	int height = rect.Height();

	CRect rcArea;
	SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL);

	int	x = rcArea.left + (rcArea.Width() - width) / 2;
	int	y = rcArea.top + (rcArea.Height() - height) / 2;

	cs.x = x;
	cs.y = y;
	cs.cx = width;
	cs.cy = height;
	cs.lpszClass = "MainWindow";

	// 指定CS_OWNDC,以提高GetDC的速度
	if (!Application->RegisterWndClass(cs.lpszClass,
		CS_VREDRAW | CS_HREDRAW | CS_OWNDC, LoadCursor(NULL, IDC_ARROW),
		(HBRUSH)::GetStockObject(BLACK_BRUSH), Application->LoadIcon(IDC_APPICON)))
		return FALSE;
	return TRUE;
}

//
// 消息处理
//
LRESULT CMainWin::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	  case WM_FIRSTACTION:		// 盘一个送来的消息
		OnFirstAction();
		break;

	  case WM_CLOSE:			// 关闭窗口
		OnClose();
		break;

	  case WM_ERASEBKGND:		// 删除背景
		return FALSE;			// 什么都不做

	  case WM_LBUTTONDOWN:		// 按下鼠标左键
		Action->LButtonDown(wParam, CPoint(lParam));
		break;

	  case WM_LBUTTONUP:		// 放开鼠标左键
		Action->LButtonUp(wParam, CPoint(lParam));
		break;

	  case WM_RBUTTONDOWN:		// 按下鼠标右键
		Action->RButtonDown(wParam, CPoint(lParam));
		break;

	  case WM_RBUTTONUP:		// 放开鼠标右键
		Action->RButtonUp(wParam, CPoint(lParam));
		break;

	  case WM_MOUSEMOVE:		// 移动鼠标
		Action->MouseMove(wParam, CPoint(lParam));
		break;

	  case WM_KEYDOWN:			// 键盘事件
		Action->KeyDown(wParam);
		break;

	  default:
		return CWindow::WindowProc(uMsg, wParam, lParam);
	}
	return 0L;
}

//
// IDLE处理
//
BOOL CMainWin::OnIdle(long count)
{
	return Action->IdleAction();
}

//
// WM_CREATE的处理
//
BOOL CMainWin::OnCreate(CREATESTRUCT *cs)
{
	LoadAccelTable(IDC_APPACCEL);

	CClientDC	dc(this);

	//  配置图片区域
	if (!MixedImage.Create(dc, WindowWidth, WindowHeight)
	 || !BackLayer.Create(WindowWidth, WindowHeight)
	 || !OverlapLayer.Create(WindowWidth, WindowHeight)) {
		MessageBox("内存无法配置。\n"
			"请先关闭其他应用程序,在重新执行这个程序。");
		return FALSE;
	}

	// 显示用图像的清除
	MixedImage.Clear();

	// 事先建立字型
	if ((hFont = CreateFont(-MessageFont, 0, 0, 0, MessageStyle, FALSE, FALSE, FALSE,
		GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS,
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "宋体")) == 0) {
		MessageBox("找不到宋体。");
		return FALSE;
	}

	SetAction(ActionNop);

	// 送出盘一个消息作为开端
	while (!PostMessage(WM_FIRSTACTION)) {
		// PostMessage 当伫列满时会错误故重复送出
#ifdef	_DEBUG
		TRACE("PostMessage Error code = %d\n", GetLastError());
#endif
		::Sleep(110);	// 重新送出消息时要稍作等待
	}
	return TRUE;
}

//
// 开始时盘一个动作
//
void CMainWin::OnFirstAction()
{
	// 一开始进行的是“主菜单”
	StartMainMenu();
}

//
// WM_CLOSE的处理
//
void CMainWin::OnClose()
{
	if (MessageBox("确定要结束了吗?", ApplicationTitle,
		MB_ICONQUESTION|MB_OKCANCEL) == IDOK) {
		::DestroyWindow(hWnd);
	}
}

//
// WM_PAINT的处理(再绘制)
//
void CMainWin::OnPaint()
{
	CPaintDC	dc(this);
	MixedImage.Draw(dc, dc.ps.rcPaint);
}

//
// WM_COMMAND的处理(Menu的处理)
//
void CMainWin::OnCommand(UINT notifyCode, UINT id, HWND ctrl)
{
	switch (id) {
	  case ID_APP_EXIT:				// 结束
		SendMessage(WM_CLOSE);
		break;

	  case ID_APP_ABOUT:			// 版本消息
		CAboutDlg().DoModal(IDD_ABOUT, hWnd);
		break;

	  case ID_STOPSCRIPT:			// 中断剧情
		if (IsStopScript() && MessageBox("您确定要停止游戏吗?", ApplicationTitle,
			MB_ICONQUESTION|MB_OKCANCEL) == IDOK)
			ScriptAction.Abort();
		break;

	  default:
		break;
	}
}

//
// 功能表初始化
//
void CMainWin::OnInitSubMenu(HMENU hMenu, UINT id)
{
	switch (id) {
	  case ID_STOPSCRIPT:			// 中断脚本
		// 中断脚本的选项只在脚本进行中有效
		EnableMenuItem(hMenu, id, IsStopScript()? MF_ENABLED: (MF_DISABLED | MF_GRAYED));
		break;
	}
}

//
// 设定动作
//
BOOL CMainWin::SetAction(int action, int param)
{
	switch (action) {
	  case ActionNop:			// 什么都不做
		Action = &NopAction;
		NopAction.Initialize(this);
		break;

	  case ActionScriptDone:	// 脚本结束
		StartMainMenu();
		break;

	  case ActionScript:		// 执行脚本
		Action = &ScriptAction;
		break;
	}
	PostMessage(WM_KICKIDLE);	// 为求慎重,传递空消息

	return TRUE;
}

//
// 执行脚本
//
bool CMainWin::StartScript(const char *name, int mode)
{
	ScriptAction.Initialize(this, mode);	// 初始化
	if (!ScriptAction.Load(name))			// 读取脚本
		return false;
	SetAction(ActionScript);				// 开始执行
	return true;
}

//
// 主菜单
//
//		显示主菜单
//
void CMainWin::StartMainMenu()
{
	if (!StartScript("main", MODE_SYSTEM))
		::DestroyWindow(hWnd);
}

//
// 显示消息
//
void CMainWin::WriteMessage(const char *msg)
{
	FormatMessage(msg);

	WaitMarkShowing = TRUE;

	ShowMessageWindow();
}

//
// 清除等待输入符号
//
void CMainWin::HideWaitMark()
{
	if (WaitMarkShowing) {
		WaitMarkShowing = FALSE;
		if (TextShow) {
			Mixing(WaitMarkRect, TextWaitMark);
			Repaint(WaitMarkRect);
		}
	}
}

//
// 显示菜单
//
void CMainWin::OpenMenu()
{
	int		maxlen = MENU_MIN_WIDTH;

	{
		CMemoryDC	memdc(0);
		HFONT	oldFont = memdc.SelectObject(hFont);

		for (int i=0; i<MenuCount; i++) {
			CSize	size;
			memdc.GetTextExtentPoint32(MenuBuffer[i].text, MenuBuffer[i].length, &size);
			if (maxlen < size.cx)
				maxlen = size.cx;
		}
		memdc.SelectObject(oldFont);
	}

	MenuRect.top = MENU_Y - ((MENU_FRAME_HEIGHT * 2)
		+ MenuCount * MENU_ITEM_HEIGHT - MENU_ITEM_SPACE);
	MenuRect.left = MENU_X;
	MenuRect.bottom = MENU_Y;
	MenuRect.right = MENU_X + (MENU_FRAME_WIDTH * 2) + maxlen;

	MenuShow = TRUE;
	Mixing(MenuRect);
	Repaint(MenuRect);
}

//
// 切换菜单是否显示
//
void CMainWin::SelectMenu(int index, bool select)
{
	if (index >= 0) {
		MenuBuffer[index].color = select? RedPixel: WhitePixel;
		CRect	rect;
		rect.left = MenuRect.left + MENU_FRAME_WIDTH;
		rect.top = MenuRect.top + MENU_FRAME_HEIGHT + MENU_ITEM_HEIGHT * index;
		rect.right = rect.left + MenuRect.Width() - MENU_FRAME_WIDTH * 2;
		rect.bottom = rect.top + MessageFont;
		Mixing(rect, MenuItem(index));
		Repaint(rect);
	}
}

//
// 显示消息区域
//
void CMainWin::ShowMessageWindow()
{
	TextDisplay = TRUE;

	TextShow = TRUE;
	Invalidate(TextRect);
	Update();
}

//
// 清除画面上的消息
//
void CMainWin::HideMessageWindow(bool update)
{
	TextDisplay = FALSE;

	if (TextShow) {
		TextShow = FALSE;
		Invalidate(TextRect);
		if (update)
			Update();
	}
}

//
// 切换消息窗口是否显示
//
void CMainWin::FlipMessageWindow()
{
	if (TextDisplay) {
		TextShow = TextShow? FALSE: TRUE;
		Invalidate(TextRect);
		Update();
	}
}

//
// 显示重叠的CG
//
void CMainWin::ShowOverlapLayer(int pos)
{
	if (OverlapShow) {		// 是要显示的状态吗?
		// 如果是显示在中间时,就删除所有之前显示的图形
		if ((OverlapFlags == Center && pos != Center)		// 中间 -> 其他
		 || (OverlapFlags != Center && pos == Center)) {	// 其他 -> 中间
			Invalidate(Position[OverlapFlags]);
			OverlapFlags = None;
			OverlapBounds.SetRectEmpty();
		}
	}
	OverlapFlags |= pos;

	OverlapBounds = Position[OverlapFlags];
	OverlapShow = TRUE;

	Invalidate(Position[pos]);
}

//
// 重叠(overlap)的消去
//
//   实际上只有显示状况变更
//
void CMainWin::HideOverlapLayer(int pos)
{
	if (OverlapShow) {		// 是要显示的状态吗?
		// 如果是显示在中间时,就删除所有之前显示的图形
		if ((OverlapFlags == Center && pos != Center)		// 中间 -> 其他
		 || (OverlapFlags != Center && pos == Center)) {	// 其他 -> 中间
			Invalidate(Position[OverlapFlags]);
			OverlapFlags = None;
			OverlapBounds.SetRectEmpty();
		}
	}
	OverlapFlags &= ~pos;

	OverlapBounds = Position[OverlapFlags];
	if (OverlapFlags == None)
		OverlapShow = FALSE;

	Invalidate(Position[pos]);
}

//
// 隐藏功能表菜单
//
void CMainWin::HideMenuWindow(bool update)
{
	if (MenuShow) {
		MenuShow = FALSE;
		Invalidate(MenuRect);
		if (update)
			Update();
	}
}

//
// 清除所有图片
//
//	pix所指定的就是填满用的色彩
//
void CMainWin::HideAllLayer(COLORREF pix)
{
	BgColor = pix;
	BackShow = FALSE;
	OverlapShow = FALSE;
	OverlapFlags = None;
	OverlapBounds.SetRectEmpty();
}

//
// CG与文字的合成
//
void CMainWin::Mixing(const CRect &rect, unsigned flags)
{
	// 背景
	if (BackShow)
		MixedImage.Copy(&BackLayer, rect);		// 如果有背景就复制
	else
		MixedImage.FillRect(rect, BgColor);		// 如果没有背景就涂满

	// 重叠
	if (OverlapShow)							// 如要要重叠就叠合
		MixedImage.MixImage(&OverlapLayer, OverlapBounds & rect);

	// 消息区域
	if (TextShow) {
		if (flags & TextMessage) {
			MixedImage.DrawFrameRect(TextRect);
			for (int i=0; i<MessageLine; i++) {
				MixedImage.DrawText(hFont, MsgX(0), MsgY(i), MsgBuffer[i]);
			}
		}
		else {
			MixedImage.FillHalfToneRect(TextRect & rect);
		}
		if (WaitMarkShowing && flags & TextWaitMark)
			MixedImage.DrawText(hFont, MsgX(WAITMARK_X), MsgY(WAITMARK_Y), "▼");
	}
	// 菜单
	if (MenuShow) {
		if (flags & MenuFrame)
			MixedImage.DrawFrameRect(MenuRect);
		else
			MixedImage.FillHalfToneRect(MenuRect & rect);

		for (int i=0; i<MenuCount; i++) {
			if (flags & MenuItem(i)) {
				MixedImage.DrawText(hFont,
					MenuRect.left + MENU_FRAME_WIDTH,
					MenuRect.top + MENU_FRAME_HEIGHT + MENU_ITEM_HEIGHT * i,
					MenuBuffer[i].text, MenuBuffer[i].color);
			}
		}
	}
}

//
// 当画面显示变更时,就再描绘
//
BOOL CMainWin::Update(bool repaint)
{
	if (!InvalidRect.IsRectEmpty()) {			// 有无效区域
		Mixing(InvalidRect);					// 合成
		if (repaint)
			Repaint(InvalidRect);				// 重绘
		InvalidRect.SetRectEmpty();				// 将无效区域设定为“无”
		return TRUE;							// Update了
	}
	return FALSE;								// 什么都没作
}

//
// 读取背景CG
//
BOOL CMainWin::LoadImageBack(const char *name)
{
	BackShow = TRUE;
	Invalidate(Position[Both]);
	return BackLayer.LoadImage(name);
}

//
// 重叠背景CG
//
BOOL CMainWin::LoadImageOverlap(const char *name, int pos)
{
	ShowOverlapLayer(pos);
	return OverlapLayer.LoadImage(name, Position[pos].left, Position[pos].top);
}

//
// 删除背景CG
//
BOOL CMainWin::ClearImageBack()
{
	BackShow = FALSE;
	Invalidate(Position[Both]);
	return TRUE;
}

//
// 不合法文字的判断
//
// 换行时要判定行首是否为不合法的文字
// 此字码为检查日文系统的日文字码,不影响中文的处理
// 读者也可依需求加入中文特殊字码的检查
//
BOOL CMainWin::Kinsoku(const char *p)
{
	switch (UC(p[0])) {
	  case 0x81:
		switch (UC(p[1])) {
		  case 0x41:		
		  case 0x42:		
		  case 0x49:		
		  case 0x48:		
		  case 0x5B:		
		  case 0x6A:		
		  case 0x76:		
		  case 0x78:		
		  case 0x99:		
		  case 0xf4:		
			return TRUE;
		}
		break;

	  case 0x82:
		switch (UC(p[1])) {
		  case 0x9f:		
		  case 0xa1:		
		  case 0xa3:		
		  case 0xa5:		
		  case 0xa7:		
		  case 0xe1:		
		  case 0xe3:		
		  case 0xe5:		
		  case 0xc1:		
			return TRUE;
		}
		break;

	  case 0x83:
		switch (UC(p[1])) {
		  case 0x40:		
		  case 0x42:		
		  case 0x44:		
		  case 0x46:		
		  case 0x48:		
		  case 0x83:		
		  case 0x85:		
		  case 0x87:		
		  case 0x62:		
			return TRUE;
		}
	}
	return FALSE;
}

#define	STR_LIMIT	(MessageWidth - 2)
#define	STR_WIDTH	(STR_LIMIT - 2)

//
// 清除消息
//
void CMainWin::ClearMessage()
{
	HideMessageWindow();

	CurX = CurY = 0;

	for (int i=0; i<MessageLine; i++)
		MsgBuffer[i][0] = 0;
}

//
// 将消息填入消息缓冲区(MsgBuffer)
//
int CMainWin::FormatMessage(const char *msg)
{
	CurX = CurY = 0;

	for (int i=0; i<MessageLine; i++)
		MsgBuffer[i][0] = 0;

	while (*msg && CurY < MessageLine) {
		if (*msg == '\n') {
			msg++;
			MsgBuffer[CurY][CurX] = 0;
			CurX = 0;
			CurY++;
		}
		else if (_ismbblead(*msg)) {
			if (CurX >= STR_LIMIT || (CurX >= STR_WIDTH && Kinsoku(msg) == 0)) {
				MsgBuffer[CurY][CurX] = 0;
				CurX = 0;
				CurY++;
			}
			MsgBuffer[CurY][CurX++] = *msg++;
			MsgBuffer[CurY][CurX++] = *msg++;
		}
		else {
			if (CurX >= STR_WIDTH) {
				MsgBuffer[CurY][CurX] = 0;
				CurX = 0;
				CurY++;
			}
			MsgBuffer[CurY][CurX++] = *msg++;
		}
	}
	if (CurX > 0 && CurY < MessageLine) {
		MsgBuffer[CurY][CurX] = 0;
		CurY++;
	}
	return CurY;
}

//
// 设定选项到菜单缓冲区
//
void CMainWin::SetMenuItem(const char *str, int anser)
{
	int		n = strlen(str);
	memcpy(MenuBuffer[MenuCount].text, str, n + 1);
	MenuBuffer[MenuCount].anser = anser;
	MenuBuffer[MenuCount].length = n;
	MenuBuffer[MenuCount].color = WhitePixel;
	MenuCount++;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -