SimpleCG小游戏开发系列(1)--扫雷

news2024/11/17 23:32:50

一、前言

        前面我们学习了SimpleCG的游戏开发框架,从本篇开始,我们用一系列小游戏的开发来加深对框架的了解.我们先以windows的经典游戏--扫雷,作为首个例子。游戏预览如下

二、框架搭建

        因为游戏程序的大体框架差不多,所以我们可以搭建一个通用的主程序。如下所示:

// GameMine.cpp : 定义控制台应用程序的入口点。
//

#include "../import/include/SimpleCG.h"


#define C_IMAGE_WIDTH			640
#define C_IMAGE_HEIGHT			480

#ifdef _DEBUG
#pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
#else
#ifdef _WIN64
#pragma comment(lib,"../import/lib/x64/MTRelease/SimpleCG_MT64.lib")
#else
#pragma comment(lib,"../import/lib/SimpleCG_MT.lib")
#endif
#endif

LRESULT OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam);

//绘制游戏
void RenderGame()
{
	
}
//更新游戏状态
void UpdateGame( UINT nElapse )
{
	static int s_nLastTick = 0;
	if( ( nElapse - s_nLastTick )<120 )
		return;

	s_nLastTick = nElapse;

}
//按键消息响应函数
LRESULT OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	switch( wParam )
	{
	case VK_SPACE:
		break;
	case VK_UP:
		break;
	case VK_DOWN:
		break;
	case VK_LEFT:
		break;
	case VK_RIGHT:
		break;
	}
	return 0;
}
LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	return false;
}
LRESULT OnLButtonUp( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	return false;
}
LRESULT OnRButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	return false;
}
LRESULT OnRButtonUp( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	return false;
}
LRESULT OnMouseMove( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	return false;
}
//初始化游戏
void InitGame(HWND hWnd)
{
	int i=0;
	int j=0;
	srand(GetTickCount());
	
	GetKeyboardInput()->onKeyDown		= OnKeyDown;
	GetMouseInput()->onMouseDownLeft	= OnLButtonDown;
	GetMouseInput()->onMouseDownRight	= OnRButtonDown;
	GetMouseInput()->onMouseUpLeft		= OnLButtonUp;
	GetMouseInput()->onMouseUpRight		= OnRButtonUp;
	GetMouseInput()->onMouseMove		= OnMouseMove;
}

int _tmain(int argc, _TCHAR* argv[])
{
	SCG_GameLoopInfo info;
	info.nFPS				= 60;
	info.nHeight			= C_IMAGE_BLOCK*g_nMapHeight+C_IMAGE_BLOCK;//C_IMAGE_HEIGHT;
	info.nWidth				= C_IMAGE_BLOCK*g_nMapWidth;//C_IMAGE_WIDTH;
	info.pFunDrawProcess	= RenderGame;
	info.pFunFrameUpdate	= UpdateGame;
	info.pFunInitGame		= InitGame;
	info.pFunInput			= NULL;

	if( !StartGameLoopEx( &info ))
		return 1;
	return 0;
}

        这个框架基本上就是前面文章所介绍的游戏开发框架。然后有了这个主框架,我们根据我们要开发的扫雷游戏,我们分别建立游戏逻辑的实现文件mine.cpp,以及头文件mine.h文件。在这两个文件中我们实现扫雷的相关逻辑,然后再把相关代码接入主程序即可。

三、游戏逻辑实现mine.cpp及mine.h文件

mine.h头文件


#ifndef _MINE_H
#define _MINE_H

#include "../import/include/SimpleCG.h"
#define C_IMAGE_BLOCK			20
enum ENUM_MAPTYPE
{
	  enumMAPTYPE_BACK
	, enumMAPTYPE_OPEN
	, enumMAPTYPE_BACKLIGHT
	, enumMAPTYPE_BACKDOWN
};
enum ENUM_MAPFLAG
{
	  enumMAPFLAG_NULL
	, enumMAPFLAG_FLAG
	, enumMAPFLAG_QUESTION
};
enum ENUM_MAPTEXT
{
	  enumMAPTEXT_NULL
	, enumMAPTEXT_NUMBER1
	, enumMAPTEXT_NUMBER2
	, enumMAPTEXT_NUMBER3
	, enumMAPTEXT_NUMBER4
	, enumMAPTEXT_NUMBER5
	, enumMAPTEXT_NUMBER6
	, enumMAPTEXT_NUMBER7
	, enumMAPTEXT_NUMBER8
	, enumMAPTEXT_NUMBER9
	, enumMAPTEXT_BOMB
};

extern int g_nMapWidth;
extern int g_nMapHeight;
//绘制内容
void Init( int nBomb, int nX, int nY  );
//计算炸弹数量
int CalBoombCount( int nX, int nY );
//绘制内容
void DrawMap( );
//绘制界面
void DrawUI(  );
//绘制单个方块,绝对坐标
void DrawBlockPos( int nX, int nY, int nType );
//绘制单个方块
void DrawBlock( int nX, int nY, int nType );
//是否在地图上
bool IsOnMap( int nX, int nY );
//坐标转化
int ScreenToMapX( int nX );
int ScreenToMapY( int nY );
//鼠标消息
LRESULT MapOnLButtonDown( WPARAM wParam, int nX, int nY );
LRESULT MapOnLButtonUp( WPARAM wParam, int nX, int nY );
LRESULT MapOnRButtonDown( WPARAM wParam, int nX, int nY );
LRESULT MapOnRButtonUp( WPARAM wParam, int nX, int nY );
LRESULT MapOnMouseMove( WPARAM wParam, int nX, int nY );
//打开操作
void DoOpen( int nX, int nY );
//设置标记
void SetFlag( int nX, int nY, int nFlag );
//设置标记
void AddFlag( int nX, int nY );
#endif

mine.cpp实现文件

/*===========================================================*\
|简介:	扫雷
|功能:	扫雷
|作者:	Bill
|主页:	http://simplecg.qqpet.com
|博客:	https://blog.csdn.net/b2b160
|贴吧:	https://tieba.baidu.com/f?kw=simplecg
|日期:	2023-09-15
\*===========================================================*/
#include "Mine.h"

int g_nMapWidth = 9;
int g_nMapHeight = 9;
int g_nMap[ 10 * 10] = {0};
int g_nMapText[ 10 * 10] = {0};
int g_nXMapPos = 0;
int g_nYMapPos = C_IMAGE_BLOCK;
int g_nBomb = 10;
int g_nLeftBomb = g_nBomb;

int g_nCurX = -1;
int g_nCurY = -1;

int g_nCurDownX = -1;
int g_nCurDownY = -1;
int g_nOpended = 0;
UINT g_nStartTime = 0;
UINT g_nGameRunning = 0;
//绘制内容
void Init( int nBomb, int nX, int nY )
{
	int i=0;
	int j=0;
	memset(g_nMap,0, sizeof(g_nMapText));
	memset(g_nMapText,0, sizeof(g_nMapText));
	int nTotal = nX*nY;
	if( nBomb>nTotal )
		nBomb = nTotal;
	g_nBomb = nBomb;
	g_nLeftBomb = g_nBomb;

	g_nMapWidth = nX;
	g_nMapHeight = nY;
	g_nOpended = 0;
	for(i=0;i<nBomb;++i)
	{
		int nBombIndex = rand() % (nX*nY);
		if( g_nMapText[nBombIndex]!=enumMAPTEXT_BOMB)
		{
			g_nMapText[nBombIndex]=enumMAPTEXT_BOMB;
		}
		else
		{
			int nStop = nBombIndex++;
			while( nBombIndex != nStop  )
			{
				if( g_nMapText[nBombIndex]!=enumMAPTEXT_BOMB )
				{
					g_nMapText[nBombIndex]=enumMAPTEXT_BOMB;
					break;
				}
				++nBombIndex;
				if(nBombIndex>=nTotal )
					nBombIndex = 0;
			}
		}
			
	}
	for(j=0;j<g_nMapHeight;++j)
	{
		for(i=0;i<g_nMapWidth;++i)
		{
			g_nMap[j*g_nMapWidth+i]=enumMAPTYPE_BACK;
			if(g_nMapText[j*g_nMapWidth+i] != enumMAPTEXT_BOMB )
				g_nMapText[j*g_nMapWidth+i]=CalBoombCount(i,j);
		}
	}
	g_nStartTime = GetTickCount();
	g_nGameRunning = TRUE;
}
//计算炸弹数量
int IsBoomb( int nX, int nY )
{
	if( nX<0 || nX>=g_nMapWidth )
		return 0;
	if( nY<0 || nY>=g_nMapHeight )
		return 0;
	if( g_nMapText[nY*g_nMapWidth+nX]==enumMAPTEXT_BOMB )
		return 1;
	return 0;
}
//计算炸弹数量
int CalBoombCount( int nX, int nY )
{
	int nCount = 0;
	if( IsBoomb(nX-1,nY-1 ) )
		++nCount;
	if( IsBoomb(nX,nY-1 ) )
		++nCount;
	if( IsBoomb(nX+1,nY-1 ) )
		++nCount;
	if( IsBoomb(nX-1,nY ) )
		++nCount;
	if( IsBoomb(nX+1,nY ) )
		++nCount;
	if( IsBoomb(nX-1,nY+1 ) )
		++nCount;
	if( IsBoomb(nX,nY+1 ) )
		++nCount;
	if( IsBoomb(nX+1,nY+1 ) )
		++nCount;
	return nCount;
}
//绘制内容
void DrawOpen( int nX, int nY )
{
	static COLORREF s_nColor[3]={RGB(200,0x0,0x0),RGB(0x0,0x0,200),RGB(22,122,11)};
	int nXPos = g_nXMapPos + nX*C_IMAGE_BLOCK;
	int nYPos = g_nYMapPos + nY*C_IMAGE_BLOCK;

	settextcolor(s_nColor[g_nMapText[nY*g_nMapWidth+nX]%3]);
	if( g_nMapText[nY*g_nMapWidth+nX]==enumMAPTEXT_BOMB)
		printfRectEx( nXPos, nYPos, C_IMAGE_BLOCK, C_IMAGE_BLOCK, DT_CENTER, _T("X"));
	else if(g_nMapText[nY*g_nMapWidth+nX]>0)
		printfRectEx( nXPos, nYPos, C_IMAGE_BLOCK, C_IMAGE_BLOCK, DT_CENTER, _T("%d"), g_nMapText[nY*g_nMapWidth+nX]);
}
//绘制内容
void DrawMap(  )
{
	int i=0;
	int j=0;
	for(j=0;j<g_nMapHeight;++j)
	{
		for(i=0;i<g_nMapWidth;++i)
		{
			switch( g_nMap[j*g_nMapWidth+i] & 0xFFFF )
			{
			case enumMAPTYPE_OPEN:
				DrawBlock( i, j, g_nMap[j*g_nMapWidth+i] );
				DrawOpen( i, j );
				break;
			case enumMAPTYPE_BACK:
				if( g_nCurDownX==i && g_nCurDownY==j )
					DrawBlock( i, j, enumMAPTYPE_BACKDOWN);
				else if( g_nCurX==i && g_nCurY==j )
					DrawBlock( i, j, enumMAPTYPE_BACKLIGHT | (g_nMap[j*g_nMapWidth+i]&0xFFFF0000) );
				else
					DrawBlock( i, j, g_nMap[j*g_nMapWidth+i] );
				break;
			}
			
		}
	}
}
//绘制界面
void DrawUI(  )
{
	int nOld;
	if( FALSE == g_nGameRunning )
		return;
	UINT nTime = GetTickCount()-g_nStartTime;
	clearrectangle(g_nXMapPos, g_nYMapPos-C_IMAGE_BLOCK, g_nXMapPos + C_IMAGE_BLOCK*g_nMapWidth, g_nYMapPos);
	nOld = settextcolor(SCG_RGB(0,0,0xFF));
	printfRectEx( g_nXMapPos, g_nYMapPos-C_IMAGE_BLOCK, C_IMAGE_BLOCK*g_nMapWidth, C_IMAGE_BLOCK, DT_VCENTER, _T("时间:%d.%d"), nTime/1000,nTime%1000);
	printfRectEx( g_nXMapPos, g_nYMapPos-C_IMAGE_BLOCK, C_IMAGE_BLOCK*g_nMapWidth, C_IMAGE_BLOCK, DT_RIGHT|DT_VCENTER, _T("炸:%d"), g_nLeftBomb);
	settextcolor(nOld);
}
//绘制单个方块,绝对坐标
void DrawBlockPos( int nX, int nY, int nType )
{
	int nFlag = (nType>>16) & 0xFFFF;
	switch( nType & 0xFFFF )
	{
	case enumMAPTYPE_OPEN:
		setlinewidth(1);
		setfillcolor(RGB(194,194,194));
		setlinecolor(RGB(125,125,125));
		fillrectangle( nX, nY, nX + C_IMAGE_BLOCK, nY + C_IMAGE_BLOCK);
		break;
	case enumMAPTYPE_BACK:
		setlinewidth(3);
		setfillcolor(RGB(194,194,194));
		setlinecolor(RGB(125,125,125));
		fillrectangle( nX+1, nY+1, nX + C_IMAGE_BLOCK-1, nY + C_IMAGE_BLOCK-1);
		setlinecolor(RGB(231,231,231));
		line(nX+2, nY+1, nX-3 + C_IMAGE_BLOCK,nY+1);
		line(nX+1, nY+2, nX+1,nY-3 + C_IMAGE_BLOCK);
		break;
	case enumMAPTYPE_BACKDOWN:
		setlinewidth(1);
		setfillcolor(RGB(194,194,194));
		setlinecolor(RGB(125,125,125));
		fillrectangle( nX, nY, nX + C_IMAGE_BLOCK, nY + C_IMAGE_BLOCK);
		break;
	case enumMAPTYPE_BACKLIGHT:
		setlinewidth(3);
		setfillcolor(RGB(221,221,221));
		setlinecolor(RGB(125,125,125));
		fillrectangle( nX+1, nY+1, nX + C_IMAGE_BLOCK-1, nY + C_IMAGE_BLOCK-1);
		setlinecolor(RGB(231,231,231));
		line(nX+2, nY+1, nX-3 + C_IMAGE_BLOCK,nY+1);
		line(nX+1, nY+2, nX+1,nY-3 + C_IMAGE_BLOCK);
		break;
	}
	if( nFlag )
	{
		switch( nFlag )
		{
		case enumMAPFLAG_FLAG:
			{
				POINT pt[]={{nX+14,nY+2},{nX+6,nY+12},{nX+14,nY+12}};
				
				setlinewidth(1);
				setfillcolor(RGB(255,0,0));
				solidpolygon( pt, sizeof(pt)/sizeof(pt[0]) );
				setfillcolor(0);
				solidrectangle( nX+13, nY+4, nX + 16, nY + C_IMAGE_BLOCK-1);
			}
			break;
		case enumMAPFLAG_QUESTION:
			settextcolor(0);
			printfRectEx( nX, nY, C_IMAGE_BLOCK, C_IMAGE_BLOCK, DT_CENTER, _T("?"));
			break;
		}
	}
}
//绘制单个方块,地图坐标
void DrawBlock( int nX, int nY, int nType )
{
	int nXPos = g_nXMapPos + nX*C_IMAGE_BLOCK;
	int nYPos = g_nYMapPos + nY*C_IMAGE_BLOCK;
	DrawBlockPos(nXPos, nYPos, nType);
}
//是否在地图上
bool IsOnMap( int nX, int nY )
{
	if(nX>=g_nXMapPos && nX<g_nXMapPos + g_nMapWidth*C_IMAGE_BLOCK && nY>=g_nYMapPos && nY<g_nYMapPos + g_nMapHeight*C_IMAGE_BLOCK )
		return true;
	return false;
}
//坐标转化
int ScreenToMapX( int nX )
{
	int nRet = -1;
	if(nX>=g_nXMapPos && nX<g_nXMapPos + g_nMapWidth*C_IMAGE_BLOCK )
	{
		nRet =( nX-g_nXMapPos)/C_IMAGE_BLOCK;
	}
	return nRet;
}
int ScreenToMapY( int nY )
{
	int nRet = -1;
	if(nY>=g_nYMapPos && nY<g_nYMapPos + g_nMapHeight*C_IMAGE_BLOCK )
	{
		nRet =( nY-g_nYMapPos)/C_IMAGE_BLOCK;
	}
	return nRet;
}
//鼠标消息
LRESULT MapOnLButtonDown( WPARAM wParam, int nX, int nY )
{
	int nMapX = ScreenToMapX(nX);
	int nMapY = ScreenToMapY(nY);
	if( g_nCurDownX != nMapX || g_nCurDownY != nMapY )
	{ 
		g_nCurDownX = nMapX;
		g_nCurDownY = nMapY;
		return true;
	}
	return false;
}
LRESULT MapOnLButtonUp( WPARAM wParam, int nX, int nY )
{
	if( g_nCurDownX >=0 && g_nCurDownX<g_nMapWidth && g_nCurDownY >=0 && g_nCurDownY<g_nMapHeight)
	{
		DoOpen( g_nCurDownX, g_nCurDownY );
		g_nCurDownX = -1;
		g_nCurDownY = -1;
		return true;
	}
	return false;
}
LRESULT MapOnRButtonDown( WPARAM wParam, int nX, int nY )
{
	return false;
}
LRESULT MapOnRButtonUp( WPARAM wParam, int nX, int nY )
{
	int nMapX = ScreenToMapX(nX);
	int nMapY = ScreenToMapY(nY);
	AddFlag( nMapX, nMapY );
	return false;
}
LRESULT MapOnMouseMove( WPARAM wParam, int nX, int nY )
{
	int nMapX = ScreenToMapX(nX);
	int nMapY = ScreenToMapY(nY);

	if( g_nCurX != nMapX || g_nCurY != nMapY )
	{
		g_nCurX = nMapX;
		g_nCurY = nMapY;
		return true;
	}
	return false;
}
void MarkOpen(int nX, int nY)
{
	g_nMap[nY*g_nMapWidth+nX] = enumMAPTYPE_OPEN;
	++g_nOpended;
	if(g_nOpended>=g_nMapWidth*g_nMapHeight-g_nBomb)
	{
		TCHAR pText[256];
		UINT nTime = GetTickCount()-g_nStartTime;
		wsprintf(pText, _T("You Win!用时%d.%d秒!是否重新开始?"), nTime/1000,nTime%1000);
		if( MessageBox(NULL,pText,_T(""),MB_YESNO) == IDYES )
			Init(g_nBomb, g_nMapWidth, g_nMapHeight);
		else
			g_nGameRunning = FALSE;
	}
}
//打开操作
void DoOpenLoop( int nX, int nY )
{
	if(g_nMap[nY*g_nMapWidth+nX] == enumMAPTYPE_OPEN)
		return;
	MarkOpen(nX, nY);
	int i=0;
	int j=0;
	for(j=-1;j<=1;++j)
	{
		for(i=-1;i<=1;++i)
		{
			if((i+nX)<0||(i+nX)>=g_nMapWidth)
				continue;
			if((j+nY)<0||(j+nY)>=g_nMapHeight)
				continue;
			if(g_nMap[(j+nY)*g_nMapWidth+(i+nX)] == enumMAPTYPE_BACK)
			{
				if(g_nMapText[(j+nY)*g_nMapWidth+(i+nX)] == enumMAPTEXT_NULL)
				{
					DoOpenLoop( i+nX, j+nY );
				}
				else if(g_nMapText[(j+nY)*g_nMapWidth+(i+nX)] != enumMAPTEXT_BOMB)
				{
					MarkOpen(i+nX, (j+nY));
				}
			}

		}
	}
}
void DoOpen( int nX, int nY )
{
	if(g_nMapText[nY*g_nMapWidth+nX] == enumMAPTEXT_BOMB )
	{
		g_nMap[nY*g_nMapWidth+nX] = enumMAPTYPE_OPEN;
		if( MessageBox(NULL,_T("游戏结束,是否重新开始?"),_T(""),MB_YESNO) == IDYES )
		{
			Init(g_nBomb, g_nMapWidth, g_nMapHeight);
			return;
		}
		else
		{
			g_nGameRunning = FALSE;
			return;
		}
	}
	else if(g_nMapText[nY*g_nMapWidth+nX] == enumMAPTEXT_NULL)
	{
		DoOpenLoop( nX, nY );
	}
	if(g_nMap[nY*g_nMapWidth+nX] != enumMAPTYPE_OPEN )
	{
		MarkOpen(nX, nY);
	}
}
//设置标记
void SetFlag( int nX, int nY, int nFlag )
{
	int nOld = g_nMap[nY*g_nMapWidth+nX];
	g_nMap[nY*g_nMapWidth+nX] = (nOld & 0xFFFF) | (nFlag<<16);
}
//设置标记
void AddFlag( int nX, int nY )
{
	if((g_nMap[nY*g_nMapWidth+nX] &0xFFFF)==enumMAPTYPE_OPEN)
		return;
	int nOld = g_nMap[nY*g_nMapWidth+nX];
	int nOldFlag = (nOld>>16)&0xFFFF;
	++nOldFlag;
	if(nOldFlag == enumMAPFLAG_FLAG )
		--g_nLeftBomb;
	else if(nOldFlag == enumMAPFLAG_QUESTION )
		++g_nLeftBomb;
	if(nOldFlag>enumMAPFLAG_QUESTION)
	{
		nOldFlag = 0;
	}
	g_nMap[nY*g_nMapWidth+nX] = (nOld & 0xFFFF) | (nOldFlag<<16);
}

四、逻辑接入主程序

在主程序中做以下几个修改,就将扫雷的逻辑接入主程序并将画面展现出来,同时接收用户的输入操作并反应。首先当然是包含逻辑头文件Mine.h

#include "Mine.h"

然后绘制画面

//绘制游戏
void RenderGame()
{
	setbackmode(enumBKM_TRANSPARENT);
	DrawMap();
	setbackmode(enumBKM_OPAQUE);
	//绘制界面
	DrawUI(  );
}

我们没有在更新函数中做任何更新,所以不需要改变UpdateGame

然后在鼠标输入操作中,我们需要判断是否在地图上并根据输入进行状态改变


LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	if( IsOnMap(nX,nY))
		return MapOnLButtonDown( wParam, nX, nY );
	return false;
}
LRESULT OnLButtonUp( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	if( IsOnMap(nX,nY))
		return MapOnLButtonUp( wParam, nX, nY );
	return false;
}
LRESULT OnRButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	if( IsOnMap(nX,nY))
		return MapOnRButtonDown( wParam, nX, nY );
	return false;
}
LRESULT OnRButtonUp( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	if( IsOnMap(nX,nY))
		return MapOnRButtonUp( wParam, nX, nY );
	return false;
}
LRESULT OnMouseMove( HWND hWnd, WPARAM wParam, int nX, int nY )
{
	if( IsOnMap(nX,nY))
		return MapOnMouseMove( wParam, nX, nY );
	return false;
}

最后在初始化阶段进行游戏初始化即可,此处初始化10个炸弹,9x9地图

Init( 10, 9, 9 );

四、代码下载

所有代码可在以下地址察看或下载,

gamemine · master · b2b160 / SimpleCG_Demo · GitCode

编译此程序需安装SimpleCG库,安装方法如下: 

SimpleCG库安装方法

如果只想执行程序可在如下地址下载

扫雷exe压缩文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1261771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

救助儿童会携手联劝公益在世界儿童日举办系列活动

2023年11月17日&#xff0c;为了呼吁家长关注对儿童情绪的关注与表达&#xff0c;救助儿童会携手联劝公益&#xff0c;以“走出情绪迷宫”为主题&#xff0c;于南丰城举办线下公益展&#xff0c;呼吁关注儿童心理健康。 本次展览由情绪迷宫、儿童艺术疗育活动、芝麻街互动三部分…

动静分离+多实例实验(nginx+tomcat)

Nginx服务器&#xff1a;192.168.188.14:80 Tomcat服务器1&#xff1a;192.168.188.11:80 Tomcat服务器2&#xff1a;192.168.188.12:8080 192.168.188.12:8081 部署Nginx负载均衡器 关闭防火墙 systemctl stop firewalld setenforce 0 安装依赖 yum -y install pcre-dev…

视频嵌套合并:视频剪辑高手分享,如何巧妙合并视频

随着社交媒体的兴起和视频制作技术的不断发展&#xff0c;视频合并已经成为了一项常见的任务。无论是娱乐、教育还是商业&#xff0c;都需要将多个视频片段合并在一起。视频嵌套合并是一种高级的视频编辑技术&#xff0c;它将两个或多个视频片段嵌套在一起&#xff0c;形成一个…

13%收入来自于贴牌代工,波司登如何闯关高端化?

寒潮已至&#xff0c;羽绒服也迎来销售旺季。 11月22日&#xff0c;#波司登13%收入来自于贴牌代工#话题冲上热搜&#xff1b;与此同时&#xff0c;波司登公布了2024财年中期的业绩预告。然而&#xff0c;根据波司登此前公布的2023财年年报显示&#xff0c;其业绩增长背后仍有隐…

Matlab R2022b 安装成功小记

Matlab R2022b 安装成功小记 前言一、 下载链接二、 安装过程小记 叮嘟&#xff01;这里是小啊呜的学习课程资料整理。好记性不如烂笔头&#xff0c;今天也是努力进步的一天。一起加油进阶吧&#xff01; 前言 windows 10系统之前安装过Matlab R2010b做基础研究&#xff0c;最…

【影刀RPA_写入日期到飞书表格】

飞书将日期写入多维表格&#xff0c;日期格式需要时毫秒级的时间戳才行。

倾斜摄影三维模型的根节点合并的轻量化技术方法分析

倾斜摄影三维模型的根节点合并的轻量化技术方法分析 倾斜摄影三维模型的根节点合并是一种轻量化技术&#xff0c;旨在减小模型数据的大小&#xff0c;提高渲染效率和加载速度。在本文中&#xff0c;我们将探讨关于倾斜摄影三维模型根节点合并的轻量化技术方法。 1、LOD&#x…

企业业务场景如何实现自动化连接?

为什么要实现企业业务场景的自动化连接&#xff1f; 可提高效率&#xff0c;自动化连接可以减少人工操作和手动干预的需求&#xff0c;从而提高业务处理的速度和效率。通过自动化连接&#xff0c;不同的系统、应用程序和流程可以自动协同工作&#xff0c;减少了人工处理的时间和…

QT基础实践之简易计算器

文章目录 简易计算器源码分享演示图第一步 界面设计第二步 设置槽第三步 计算功能实现 简易计算器 源码分享 链接&#xff1a;https://pan.baidu.com/s/1Jn5fJLYOZUq77eNJ916Kig 提取码&#xff1a;qwer 演示图 第一步 界面设计 这里直接用了ui界面&#xff0c;如果想要自己…

11 OAuth2.0实战:网关统一认证授权

上一节介绍了认证中心,这节介绍下网关如何集成认证中心实现网关的统一认证授权。 木谷博客系统的整个认证授权架构设计如下图: 网关在这里的主要功能就是6-8这三步: 校验token:对令牌的过期时间、签名进行校验鉴权:对令牌的权限进行校验转发:解析令牌中的相关信息,通过…

没有哈希时间锁定合约的跨链原子交换

在上一篇文章中&#xff0c;我们介绍了使用哈希时间锁定合约&#xff08;HTLC&#xff09;的跨链原子交换实现。 今天&#xff0c;我们介绍一种无需 HTLC 即可实现的替代方法。 这将原子交换扩展到缺乏哈希锁和时间锁的区块链。 使用 SPV 证明交易已被挖掘 让我们按照商定的价…

最佳软件配置管理工具(16款SCM工具)

配置管理&#xff08;CM&#xff09;是一种系统工程方法&#xff0c;用于在产品的整个生命周期内建立和维持产品的性能&#xff0c;功能和物理属性与其设计&#xff0c;要求和操作信息的一致性。 它们为您的组织带来了成本效益和更好的时间管理。 当今市场充斥着各种配置管理工…

本机putty无法连接到虚拟机中kali操作系统

sudo apt-get install -y openssh-server安装一下软件&#xff0c;我这里已经安装好了&#xff0c;所以没有安装过程了。 firewall-cmd --zonepublic --remove-port22/tcp --permanent想要打开22端口&#xff0c;发现报错如下&#xff1a; Could not find command-not-found…

封装可多选的组件(Autocomplete)

一。组件库Material UI 1.1 地址 https://v4.mui.com/zh/getting-started/installation/ 1.2 简介 自称世界上最受欢迎的React UI组件库(能看到这里的基本用法应该都清楚了&#xff0c;我就不重复了) 二。效果展示 三。代码展示 import React from reactimport { useField, us…

利用ambari搭建Hbase高可用

初始环境&#xff1a; 节点名称服务名ambari-hadoop1ambari-hadoop2region serverambari-hadoop3hmater、 region server 计划为ambari-hadoop1添加hmaster&#xff0c;以避免hmaster的单点故障、 step1&#xff1a;添加备用Hmaster step2&#xff1a;选择ambari-hadoop1作为…

ArkTS-页面转场动画

页面转场动画 在全局pageTransition方法内配置页面入场和页面退场时的自定义转场动效 两个页面间发生跳转&#xff0c;一个页面消失&#xff0c;另一个页面出现&#xff0c;这时可以配置各自页面的页面转场参数实现自定义的页面转场效果。页面转场效果写在pageTransition函数中…

Non-constant range: argument must be an integer literal 警告的解决方法

升级Xcode以后&#xff0c;在SwiftUI开发过程中&#xff0c;使用ForEach语句的时候&#xff0c;遇到一个“Non-constant range: argument must be an integer literal ”的警告。如下图 其解决方法比较简单。在之后加上id:\.self 。 至于为什么这么加没有找到原因。姑且做个记录…

如何确定先做哪件事情。

问题描述&#xff1a;工作或者生活中&#xff0c;有许多件事情&#xff0c;我们应该先做那件事情。 解决办法&#xff1a;重要紧急的四象限法则。具体如下所示&#xff1a; -----------------------------------------------------------------------------------------------…

ubuntu22.04新机使用(换源,下载软件,安装显卡驱动)

换源 国内有很多Ubuntu的镜像源&#xff0c;包括阿里的、网易的&#xff0c;还有很多教育网的源&#xff0c;比如&#xff1a;清华源、中科大源。推荐使用中科大源&#xff0c;快得很。 /etc/apt/sources.list编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前…

npm-工具包

npm-工具包 npm 介绍 npm&#xff08;Node Package Manager&#xff09;是用于管理和共享Node.js包&#xff08;包括代码、工具和资源&#xff09;的包管理工具 常用命令 局部安装包 npm install <package-name>: 安装指定的包 npm install <package-name> --save…