#include "pch.h"
#include "framework.h"
#include "GoldMinerGame.h"
#include "GoldMinerGameDlg.h"
#include "Login.h"
#include "afxdialogex.h"
#include <cmath>
#include <cstdlib>
#include <ctime>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNAMIC(CGoldMinerGameDlg, CDialogEx)
CGoldMinerGameDlg::CGoldMinerGameDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_GOLDMINERGAME_DIALOG, pParent)
, m_bHookOut(FALSE)
, m_bRetracting(FALSE)
, m_dAngle(0.0)
, m_nAngleDir(1)
, m_nScore(0)
, m_nHookSpeed(5)
, m_nGameMode(0)
, m_nLevel(1)
, m_nItemsCollected(0)
, m_bFirstLaunch(TRUE)
, m_nCurrentRopeLen(50)
, m_hIcon(nullptr)
{
// 初始化随机数生成器
srand((unsigned int)time(NULL));
// 分配物品数组内存
m_pGolds = new Item[m_nGoldNum];
m_pStones = new Item[m_nStoneNum];
// 初始化钩子物品
m_hookItem = Item();
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CGoldMinerGameDlg::~CGoldMinerGameDlg()
{
// 释放物品数组内存
delete[] m_pGolds;
delete[] m_pStones;
}
void CGoldMinerGameDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CGoldMinerGameDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
ON_WM_DESTROY()
END_MESSAGE_MAP()
BOOL CGoldMinerGameDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将"关于..."菜单项添加到系统菜单中
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置对话框图标
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
// 显示登录对话框
CLogin loginDlg;
if (loginDlg.DoModal() == IDOK)
{
m_nGameMode = loginDlg.GetSelectedMode();
m_nHookSpeed = (m_nGameMode == 1) ? 7 : 5;
}
else
{
EndDialog(IDCANCEL);
return FALSE;
}
// 初始化游戏元素
CRect rect;
GetClientRect(&rect);
m_ptHookStart = CPoint(rect.Width() / 2, 50);
m_ptRopeEnd = m_ptHookStart;
m_ptHookRetractStart = m_ptHookStart;
// 初始化游戏
InitGame();
// 启动定时器
SetTimer(1, 10, NULL);
return TRUE;
}
void CGoldMinerGameDlg::InitGame()
{
CRect rect;
GetClientRect(&rect);
// 计算游戏区域
const int nTopMargin = 50;
const int nBottomMargin = 50;
const int nSideMargin = 50;
const int nGameHeight = rect.Height() - nTopMargin - nBottomMargin;
const int nGameWidth = rect.Width() - 2 * nSideMargin;
const int nLayerHeight = nGameHeight / 3;
// 初始化黄金
for (int i = 0; i < m_nGoldNum; i++)
{
int layer = (i < m_nGoldNum / 2) ? 0 : 1;
int y = nTopMargin + layer * nLayerHeight + 20;
y = min(y, m_nSwingAreaBottom - 50);
int x = m_nSwingAreaLeft + 20 + rand() % (m_nSwingAreaRight - m_nSwingAreaLeft - 40);
m_pGolds[i].rcBounds.SetRect(
x, y,
x + 20 + rand() % 20,
y + 20 + rand() % 20
);
m_pGolds[i].nValue = 100 + rand() % 50;
m_pGolds[i].type = GOLD;
m_pGolds[i].bExists = true;
}
// 初始化石头
for (int i = 0; i < m_nStoneNum; i++)
{
int y = nTopMargin + 2 * nLayerHeight + 20;
y = min(y, m_nSwingAreaBottom - 50);
int x = m_nSwingAreaLeft + 20 + rand() % (m_nSwingAreaRight - m_nSwingAreaLeft - 40);
m_pStones[i].rcBounds.SetRect(
x, y,
x + 15 + rand() % 15,
y + 15 + rand() % 15
);
m_pStones[i].nValue = 10 + rand() % 20;
m_pStones[i].type = STONE;
m_pStones[i].bExists = true;
}
// 重置钩子状态
m_hookItem.bExists = false;
m_dAngle = 0.0;
m_nCurrentRopeLen = 50;
}
void CGoldMinerGameDlg::RefreshGoldAndStone()
{
CRect rect;
GetClientRect(&rect);
const int nTopMargin = 50;
const int nBottomMargin = 50;
const int nSideMargin = 50;
const int nGameHeight = rect.Height() - nTopMargin - nBottomMargin;
const int nGameWidth = rect.Width() - 2 * nSideMargin;
const int nLayerHeight = nGameHeight / 3;
// 刷新未被收集的黄金
for (int i = 0; i < m_nGoldNum; i++)
{
if (!m_pGolds[i].bExists)
{
int layer = (i < m_nGoldNum / 2) ? 0 : 1;
int y = nTopMargin + layer * nLayerHeight + 20;
y = min(y, m_nSwingAreaBottom - 50);
int x = m_nSwingAreaLeft + 20 + rand() % (m_nSwingAreaRight - m_nSwingAreaLeft - 40);
m_pGolds[i].rcBounds.SetRect(
x, y,
x + 20 + rand() % 20,
y + 20 + rand() % 20
);
m_pGolds[i].bExists = true;
}
}
// 刷新未被收集的石头
for (int i = 0; i < m_nStoneNum; i++)
{
if (!m_pStones[i].bExists)
{
int y = nTopMargin + 2 * nLayerHeight + 20;
y = min(y, m_nSwingAreaBottom - 50);
int x = m_nSwingAreaLeft + 20 + rand() % (m_nSwingAreaRight - m_nSwingAreaLeft - 40);
m_pStones[i].rcBounds.SetRect(
x, y,
x + 15 + rand() % 15,
y + 15 + rand() % 15
);
m_pStones[i].bExists = true;
}
}
}
void CGoldMinerGameDlg::UpdateScore(int points)
{
m_nScore += points;
CString strScore;
strScore.Format(_T("黄金矿工 - 分数:%d 关卡:%d"), m_nScore, m_nLevel);
SetWindowText(strScore);
}
void CGoldMinerGameDlg::UpdateRopeAngle()
{
if (!m_bHookOut && !m_bRetracting)
{
m_dAngle += m_nAngleDir * 0.03;
if (m_dAngle > 1.5 || m_dAngle < -1.5)
{
m_nAngleDir *= -1;
}
}
}
void CGoldMinerGameDlg::CheckCollision()
{
if (!m_bHookOut || m_hookItem.bExists) return;
int hookX = m_ptHookStart.x + (int)(m_nCurrentRopeLen * sin(m_dAngle));
int hookY = m_ptHookStart.y + (int)(m_nCurrentRopeLen * cos(m_dAngle));
// 扩大碰撞检测范围,增加5像素的容差
CRect rcHook(hookX - 20, hookY - 20, hookX + 20, hookY + 20);
// 检测与黄金的碰撞
for (int i = 0; i < m_nGoldNum; i++)
{
if (m_pGolds[i].bExists)
{
// 为黄金添加额外的容差区域
CRect goldArea = m_pGolds[i].rcBounds;
goldArea.InflateRect(5, 5); // 扩大5像素
if (rcHook.IntersectRect(rcHook, goldArea))
{
m_pGolds[i].bExists = false;
m_hookItem = m_pGolds[i];
m_hookItem.bExists = true;
m_bHookOut = FALSE;
m_bRetracting = TRUE;
return;
}
}
}
// 检测与石头的碰撞(类似黄金的处理)
for (int i = 0; i < m_nStoneNum; i++)
{
if (m_pStones[i].bExists)
{
// 为石头添加额外的容差区域
CRect stoneArea = m_pStones[i].rcBounds;
stoneArea.InflateRect(3, 3); // 石头容差小一些
if (rcHook.IntersectRect(rcHook, stoneArea))
{
m_pStones[i].bExists = false;
m_hookItem = m_pStones[i];
m_hookItem.bExists = true;
m_bHookOut = FALSE;
m_bRetracting = TRUE;
return;
}
}
}
}
void CGoldMinerGameDlg::CheckGameEnd()
{
bool allCollected = true;
for (int i = 0; i < m_nGoldNum; i++)
{
if (m_pGolds[i].bExists)
{
allCollected = false;
break;
}
}
for (int i = 0; i < m_nStoneNum; i++)
{
if (m_pStones[i].bExists)
{
allCollected = false;
break;
}
}
if (allCollected)
{
m_nLevel++;
m_nItemsCollected = 0;
RefreshGoldAndStone();
CString strMsg;
strMsg.Format(_T("恭喜通过第%d关!准备进入第%d关"), m_nLevel - 1, m_nLevel);
MessageBox(strMsg, _T("关卡提示"), MB_OK);
}
}
void CGoldMinerGameDlg::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
CBrush brushSky(RGB(135, 206, 235));
dc.FillRect(&rect, &brushSky);
if (IsIconic())
{
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
// 绘制矿工
CRect rcMiner(m_ptHookStart.x - 30, 30, m_ptHookStart.x + 30, 60);
CBrush brushMiner(RGB(139, 69, 19));
dc.SelectObject(&brushMiner);
dc.Rectangle(rcMiner);
dc.SetTextColor(RGB(255, 255, 255));
dc.TextOutW(rcMiner.left + 5, rcMiner.top + 5, _T("矿工"));
// 绘制地面
CBrush brushGround(RGB(34, 139, 34));
dc.FillRect(CRect(0, rect.bottom - 50, rect.right, rect.bottom), &brushGround);
// 计算绳子末端位置
int ropeEndX = m_ptHookStart.x + (int)(m_nCurrentRopeLen * sin(m_dAngle));
int ropeEndY = m_ptHookStart.y + (int)(m_nCurrentRopeLen * cos(m_dAngle));
// 限制绳子在摆动区域内
ropeEndX = max(m_nSwingAreaLeft, min(ropeEndX, m_nSwingAreaRight));
ropeEndY = max(m_nSwingAreaTop, min(ropeEndY, m_nSwingAreaBottom));
m_ptRopeEnd = CPoint(ropeEndX, ropeEndY);
// 绘制绳子
CPen penRope(PS_SOLID, 2, RGB(139, 69, 19));
dc.SelectObject(&penRope);
dc.MoveTo(m_ptHookStart);
dc.LineTo(m_ptRopeEnd);
// 绘制钩子
CPen penHook(PS_SOLID, 3, RGB(0, 0, 0));
dc.SelectObject(&penHook);
CPoint hookPoints[3];
hookPoints[0] = m_ptRopeEnd;
hookPoints[1] = CPoint(m_ptRopeEnd.x + 10, m_ptRopeEnd.y + 10);
hookPoints[2] = CPoint(m_ptRopeEnd.x - 10, m_ptRopeEnd.y + 10);
dc.Polyline(hookPoints, 3);
CRect rcHookHead(m_ptRopeEnd.x - 5, m_ptRopeEnd.y + 10,
m_ptRopeEnd.x + 5, m_ptRopeEnd.y + 20);
dc.Rectangle(rcHookHead);
// 绘制黄金
CBrush brushGold(RGB(255, 215, 0));
for (int i = 0; i < m_nGoldNum; i++)
{
if (m_pGolds[i].bExists)
{
dc.SelectObject(&brushGold);
dc.Ellipse(m_pGolds[i].rcBounds);
}
}
// 绘制石头
CBrush brushStone(RGB(128, 128, 128));
for (int i = 0; i < m_nStoneNum; i++)
{
if (m_pStones[i].bExists)
{
dc.SelectObject(&brushStone);
dc.Rectangle(m_pStones[i].rcBounds);
}
}
// 绘制勾住的物品
if (m_hookItem.bExists)
{
if (m_hookItem.type == GOLD)
{
dc.SelectObject(&brushGold);
dc.Ellipse(CRect(m_ptRopeEnd.x - 15, m_ptRopeEnd.y + 20,
m_ptRopeEnd.x + 15, m_ptRopeEnd.y + 50));
}
else
{
dc.SelectObject(&brushStone);
dc.Rectangle(CRect(m_ptRopeEnd.x - 15, m_ptRopeEnd.y + 20,
m_ptRopeEnd.x + 15, m_ptRopeEnd.y + 50));
}
}
}
CDialogEx::OnPaint();
}
void CGoldMinerGameDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_bHookOut && !m_bRetracting)
{
m_bHookOut = TRUE;
m_ptHookRetractStart = m_ptRopeEnd;
}
else if (m_bHookOut)
{
m_bHookOut = FALSE;
m_bRetracting = TRUE;
}
CDialogEx::OnLButtonDown(nFlags, point);
}
void CGoldMinerGameDlg::OnTimer(UINT_PTR nIDEvent)
{
UpdateRopeAngle();
if (m_bHookOut)
{
m_nCurrentRopeLen += 4;
CheckCollision();
if (!m_bRetracting)
{
int hookX = m_ptHookStart.x + (int)(m_nCurrentRopeLen * sin(m_dAngle));
int hookY = m_ptHookStart.y + (int)(m_nCurrentRopeLen * cos(m_dAngle));
if (m_nCurrentRopeLen >= m_nRopeMaxLen ||
hookX <= m_nSwingAreaLeft ||
hookX >= m_nSwingAreaRight ||
hookY >= m_nSwingAreaBottom)
{
m_bHookOut = FALSE;
m_bRetracting = TRUE;
}
}
}
else if (m_bRetracting)
{
m_nCurrentRopeLen -= 3;
if (m_nCurrentRopeLen <= 50)
{
m_nCurrentRopeLen = 50;
m_bRetracting = FALSE;
if (m_hookItem.bExists)
{
UpdateScore(m_hookItem.nValue);
m_hookItem.bExists = false;
CheckGameEnd();
}
}
}
Invalidate();
CDialogEx::OnTimer(nIDEvent);
}
void CGoldMinerGameDlg::OnDestroy()
{
KillTimer(1);
CDialogEx::OnDestroy();
}
HCURSOR CGoldMinerGameDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}这是源文件
#pragma once
// 防止头文件被重复包含
#pragma once
#include "afxdialogex.h"
// 物品类型枚举
enum ItemType { GOLD, STONE };
// 物品结构体
struct Item {
CRect rcBounds; // 位置和大小
int nValue; // 价值
ItemType type; // 类型
bool bExists; // 是否存在
Item() : rcBounds(0, 0, 0, 0), nValue(0), type(GOLD), bExists(false) {}
};
class CGoldMinerGameDlg : public CDialogEx
{
DECLARE_DYNAMIC(CGoldMinerGameDlg)
public:
CGoldMinerGameDlg(CWnd* pParent = nullptr);
virtual ~CGoldMinerGameDlg();
protected:
virtual void DoDataExchange(CDataExchange* pDX);
DECLARE_MESSAGE_MAP()
private:
// 游戏常量
const int m_nGoldNum = 5; // 黄金数量
const int m_nStoneNum = 3; // 石头数量
const int m_nRopeMaxLen = 400; // 绳子最大长度
// 摆动区域定义
const int m_nSwingAreaTop = 80; // 摆动区域顶部
const int m_nSwingAreaBottom = 450; // 摆动区域底部
const int m_nSwingAreaLeft = 150; // 摆动区域左侧
const int m_nSwingAreaRight = 490; // 摆动区域右侧
CPoint m_ptHookStart; // 钩子固定点
CPoint m_ptRopeEnd; // 绳子末端位置
CPoint m_ptHookRetractStart; // 钩子收回起始点
BOOL m_bHookOut; // 是否正在发射
BOOL m_bRetracting; // 是否正在收回
double m_dAngle; // 当前摆动角度
int m_nAngleDir; // 摆动方向
int m_nScore; // 分数
int m_nHookSpeed; // 钩子速度
int m_nGameMode; // 游戏模式
int m_nLevel; // 关卡
int m_nItemsCollected; // 收集的物品数
int m_nCurrentRopeLen; // 当前绳子长度
// 物品数组
Item* m_pGolds;
Item* m_pStones;
Item m_hookItem; // 钩子勾住的物品
BOOL m_bFirstLaunch;
// 函数声明
void InitGame();
void RefreshGoldAndStone();
void UpdateScore(int points);
void UpdateRopeAngle();
void CheckCollision();
void CheckGameEnd();
public:
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnDestroy();
afx_msg HCURSOR OnQueryDragIcon();
HICON m_hIcon;
};这是头文件
为什么钩子一直定在同一个位置,怎样让他摆动
最新发布