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

📄 main.c

📁 有趣的粒子爆炸效果....Win32 编程 [代码性质] VC完整应用程序代码 [代码作者] a1324@yeah.net [文件大小] 13K
💻 C
字号:
#include <windows.h>
#include <windef.h>
#include <commctrl.h>
#include <commdlg.h>
#include <wingdi.h>

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <stdio.h>
#include <math.h>

#include "resource.h"
#include "cannon.h"

#define		MYSIDEVIEW	2000

const	char*	str[] =
{
	"幻\0", "炎\0", "28\0", "舰\0","队\0"
};

LRESULT CALLBACK DemoDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK DefaultWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

HINSTANCE	hinst;
HWND		hMainWindow;
HDC			hBufferDC;
HBITMAP		hBufferBitmap;

void	InitializeVariables(void);
void	DrawLine(HDC hdc, int h1, int v1, int h2, int v2, int thk, COLORREF clr);
void	DrawRectangle(HDC hdc, RECT *r, int thk, COLORREF clr);
void	DrawCircle(HDC hdc, int cx, int cy, int r, COLORREF clr);
void	DrawString(HDC hdc, int x, int y, LPCSTR lpszString, int size, int ptsz);
int		DoSimulation(void);

BOOL	UpdateParticleState(TParticle *p, int dtime);
void	CreateParticleExplosion(int x, int y, int force, int life, float gravity, float angle);
BOOL	DrawParticleExplosion(HDC hdc);
int		tb_Rnd(int min, int max);
int		tb_Round(double x);

int APIENTRY WinMain(
					 HINSTANCE hInstance, 
					 HINSTANCE hPrevInstance, 
					 LPSTR lpCmdLine, 
					 int nCmdShow
					 )
{
	DLGPROC		dlgprc;
	int			retval = 0;
	
	dlgprc	= (DLGPROC)MakeProcInstance(DemoDlgProc, hInstance);
	retval	= DialogBox(hInstance, MAKEINTRESOURCE(IDD_DEMODIALOG), NULL, dlgprc);
	if (-1 == retval)
	{
		MessageBox(NULL, "Error", "Can`t create dialog box.", MB_OK);
		return FALSE;
	}
	FreeProcInstance((FARPROC)dlgprc);
	
	return (FALSE);
}

LRESULT CALLBACK DemoDlgProc(
							 HWND	hDlg,
							 UINT	message,
							 WPARAM	wParam,
							 LPARAM	lParam
							 )
{
	static	HWND	hTopView;
	static	HWND	hSideView;
	WNDCLASSEX		wclass;
	char			str[16];
	BOOL			status;
	RECT			r;
	HDC				hdc;
	
	switch (message)	
	{
	case WM_INITDIALOG:
		// 这里初始化对话框
		{
			// 设置一个子窗口类以便我们能创建两个
			// 窗口来画两个轨道视图
			wclass.cbSize			=	sizeof(wclass);
			wclass.style			=	CS_HREDRAW | CS_VREDRAW;
			wclass.lpfnWndProc		=	DefaultWndProc;
			wclass.cbClsExtra		=	0;
			wclass.cbWndExtra		=	0;
			wclass.hInstance		=	hinst;	// ?????
			wclass.hIcon			=	NULL;
			wclass.hCursor			=	NULL;
			wclass.hbrBackground	=	(HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
			wclass.lpszMenuName		=	NULL;
			wclass.lpszClassName	=	"ViewClass";
			wclass.hIconSm			=	NULL;
			
			RegisterClassEx(&wclass);
			
			// 为边视图创建一个子窗口
			hSideView = CreateWindowEx(
				0L,
				"ViewClass",
				NULL,
				WS_CHILD | WS_VISIBLE | WS_BORDER,
				200,
				10 + 10,
				400,
				400,
				hDlg,
				NULL,
				hinst,
				NULL
				);
			
			// 以我们的ID MYSIDEVIEW来标记窗口,这样我们
			// 能够在画窗口时将它与顶视图窗口区分开。
			SetWindowLong(hSideView, GWL_USERDATA, MYSIDEVIEW);
			
			
			ShowWindow(hSideView, SW_SHOW);
			
			// 现在以变量中的默认值来初始化对话框中的所有编辑控件
			
			// 设置所有变量的默认值
			InitializeVariables();
			
			// 现在将每个变量值转换为字符串并
			// 设置适当的edit控件
			sprintf(str, "%d", xc);
			SetDlgItemText(hDlg, IDC_X, str);
			
			sprintf(str, "%d", yc);
			SetDlgItemText(hDlg, IDC_Y, str);
			
			sprintf(str, "%d", V0);
			SetDlgItemText(hDlg, IDC_V0, str);
			
			sprintf(str, "%d", Duration);
			SetDlgItemText(hDlg, IDC_DURATION, str);
			
			sprintf(str, "%f", Gravity);
			SetDlgItemText(hDlg, IDC_GRAVITY, str);
			
			sprintf(str, "%f", Angle);
			SetDlgItemText(hDlg, IDC_ANGLE, str);
			
			// 创建一个作图缓冲区
			hdc				= GetDC(hSideView);
			hBufferDC		= CreateCompatibleDC(hdc);
			hBufferBitmap	= CreateCompatibleBitmap(hdc, 400, 400);
			ReleaseDC(hSideView, hdc);
			
			// hBufferBitmap = CreateBitmap(500, 200, 1, 24, NULL);
			
			SelectObject(hBufferDC, hBufferBitmap);
			
			/***********************/
			bShowTrack	= FALSE;
			CheckDlgButton(hDlg, IDC_CHECK_TRACK, BST_UNCHECKED);
			/***********************/
		}	// End of case WM_INITDIALOG
		break;
		
	case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
			case IDC_RANDOM:
			case IDC_FIRE:
				// 以编辑控件显示的值更新变量
				
				if (IDC_FIRE == LOWORD(wParam))
				{
					GetDlgItemText(hDlg, IDC_X, str, 15);
					xc	= atoi(str);
					
					GetDlgItemText(hDlg, IDC_Y, str, 15);
					yc	= atoi(str);
					
					GetDlgItemText(hDlg, IDC_V0, str, 15);
					V0	= atoi(str);
					
					GetDlgItemText(hDlg, IDC_DURATION, str, 15);
					Duration	= atoi(str);
					
					GetDlgItemText(hDlg, IDC_GRAVITY, str, 15);
					Gravity	= atoi(str);
					
					GetDlgItemText(hDlg, IDC_ANGLE, str, 15);
					Angle	= atoi(str);
				}	// End of if (IDC_FIRE == LOWORD(wParam))
				else
				{
					xc			= tb_Rnd(100, 300);
					yc			= tb_Rnd(100, 300);
					V0			= tb_Rnd(10, 100);
					Duration	= tb_Rnd(2000, 6000);
					Gravity		= tb_Rnd(0, 100);
					Angle		= 999;
					
					sprintf(str, "%d", xc);
					SetDlgItemText(hDlg, IDC_X, str);
					
					sprintf(str, "%d", yc);
					SetDlgItemText(hDlg, IDC_Y, str);
					
					sprintf(str, "%d", V0);
					SetDlgItemText(hDlg, IDC_V0, str);
					
					sprintf(str, "%d", Duration);
					SetDlgItemText(hDlg, IDC_DURATION, str);
					
					sprintf(str, "%f", Gravity);
					SetDlgItemText(hDlg, IDC_GRAVITY, str);
					
					sprintf(str, "%f", Angle);
					SetDlgItemText(hDlg, IDC_ANGLE, str);
				}	// End of else (IDC_FIRE == LOWORD(wParam))
				
				CreateParticleExplosion(xc, yc, V0, Duration, Gravity, Angle); 
				r.left		= 0;
				r.right		= 400;
				r.top		= 0;
				r.bottom	= 400;
				
				// 初始化时间和状态变量
				status	= TRUE;
				
				// 开始单步模拟
				// 直到目标被击中,炮弹击中了地面或sim。时间到。
				while (status)
				{
					// 背景涂黑
					if (!bShowTrack)
					{
						DrawRectangle(hBufferDC, &r, 1, RGB(0, 0, 0));
					}
					
					// 绘制粒子爆炸
					status	= DrawParticleExplosion(hBufferDC);
					
					hdc	= GetDC(hSideView);
					
					if (!BitBlt(
						hdc,
						0,
						0,
						r.right,
						r.bottom,
						hBufferDC,
						0,
						0,
						SRCCOPY
						)
						)
					{
						MessageBox(NULL, "BitBlt failed", "Error", MB_OK);
						status	= FALSE;
					}
					
					ReleaseDC(hSideView, hdc);
				}	// End of while (status)
				break;
				
			case ID_CLOSE:
				{
					// 清除子窗口并关闭对话框
					DeleteObject(hBufferBitmap);
					DeleteDC(hBufferDC);
					DestroyWindow(hSideView);
					EndDialog(hDlg, 1);
				}	// End of case ID_CLOSE
				break;
				
			case IDCANCEL:
				{
					// 清除子窗口并关闭对话框
					DeleteObject(hBufferBitmap);
					DeleteDC(hBufferDC);
					DestroyWindow(hSideView);
					EndDialog(hDlg, 0);
				}	// End of case IDCANCEL
				break;
				
				/***********************/
			case IDC_CHECK_TRACK:
			/*
			bShowTrack = !bShowTrack;
			CheckDlgButton(
			hDlg, 
			IDC_CHECK_TRACK, 
			bShowTrack ? BST_CHECKED : BST_UNCHECKED);
				*/
				bShowTrack = IsDlgButtonChecked(hDlg, IDC_CHECK_TRACK);
				CheckDlgButton(
					hDlg, 
					IDC_CHECK_TRACK, 
					bShowTrack ? BST_CHECKED : BST_UNCHECKED);
				break;
				/***********************/
			}	// End of switch (LOWORD(wParam))
		}	// End of case WM_COMMAND
		break;
		
		default:
			return (FALSE);
	}	// End of switch (message)
	
	return (TRUE);
}

//------------------------------------------------------
// 子窗口的默认处理函数
//------------------------------------------------------
LRESULT CALLBACK DefaultWndProc(
								HWND	hwnd,
								UINT	message,
								WPARAM	wParam,
								LPARAM	lParam
								)
{
	switch (message)
	{
	}
	
	return	DefWindowProc(hwnd, message, wParam, lParam);
}

void InitializeVariables(void)
{
	xc			= 200;
	yc			= 100;
	V0			= 75;
	Duration	= 4000;
	Gravity		= 30.0f;
	Angle		= 999;
}

void DrawRectangle(
				   HDC		hdc,
				   RECT		*r,
				   int		thk,
				   COLORREF	clr
				   )
{
	HBRUSH		CurrentBrush;
	HBRUSH		OldBrush;
	HPEN		CurrentPen;
	HPEN		OldPen;
	COLORREF	FColor = clr;
	COLORREF	BColor = clr;
	
	if (NULL == hdc || NULL == r)
	{
		return;
	}
	
	CurrentBrush	= CreateSolidBrush(BColor);
	OldBrush		= (HBRUSH)SelectObject(hdc, CurrentBrush);
	CurrentPen		= CreatePen(PS_SOLID, thk, FColor);
	OldPen			= (HPEN)SelectObject(hdc, CurrentPen);
	
	Rectangle(hdc, r->left, r->top, r->right, r->bottom);
	
	SelectObject(hdc, OldBrush);
	SelectObject(hdc, OldPen);
	DeleteObject(CurrentBrush);
	DeleteObject(CurrentPen);
}

void DrawCircle(
				HDC			hdc,
				int			cx,
				int			cy,
				int			r,
				COLORREF	clr
				)
{
	HBRUSH		CurrentBrush;
	HBRUSH		OldBrush;
	HPEN		CurrentPen;
	HPEN		OldPen;
	COLORREF	FColor = clr;
	COLORREF	BColor = clr;
	
	static	int	num;
	
	if (NULL == hdc)
	{
		return;
	}
	
	CurrentBrush	= CreateSolidBrush(BColor);
	OldBrush		= (HBRUSH)SelectObject(hdc, CurrentBrush);
	CurrentPen		= CreatePen(PS_SOLID, 1, FColor);
	OldPen			= (HPEN)SelectObject(hdc, CurrentPen);
	
	/*
	Ellipse(hdc, cx - r, cy - r, cx + r, cy + r);
	*/
	
	/***********************/
	/*呵呵~~这样做的话由于有粒子死亡,所以后面的字会乱*/
	SetBkColor(hdc, RGB(0,0,0));
	SetTextColor(hdc, clr);
	TextOut(hdc, cx, cy, str[(num % 5)], strlen(str[(num % 5)]));
	num ++;
	/***********************/
	
	SelectObject(hdc, OldBrush);
	SelectObject(hdc, OldPen);
	DeleteObject(CurrentBrush);
	DeleteObject(CurrentPen);
}

int tb_Rnd(int min, int max)
{
	int number;
	
	number = (((abs(rand()) % (max - min + 1)) + min));
	
	if (number > max)
	{
		number = max;
	}
	
	if (number < min)
	{
		number = min;
	}
	
	return number;
}

/////////////////////////////////////////////
// 浮点数的取整(四舍五入)
/////////////////////////////////////////////
int tb_Round(double x)
{
	int		result;
	double	remainder;
	
	result	= (int)(x);
	
	if (0 == result)
		return 0;
	
	remainder = fmod(x, (double)result);	// 取余数
	if (0.5 <= remainder)
		result ++;
	
	return result;
}

void CreateParticleExplosion(
							 int	x,
							 int	y,
							 int	Vinit,
							 int	life,
							 float	gravity,
							 float	angle
							 )
{
	int		i;
	int		m;	// 偏向型
	float	f;	// 存活时间百分比
	
	Explosion.Active	= TRUE;
	Explosion.x			= x;
	Explosion.y			= y;
	Explosion.V0		= Vinit;
	
	for (i = 0; i < _MAXPARTICLES; i ++)
	{
		Explosion.p[i].x	= 0;
		Explosion.p[i].y	= 0;
		Explosion.p[i].vi	= tb_Rnd(Vinit/2, Vinit);
		
		if (999 > angle)
		{
			if (0 == tb_Rnd(0, 1))
				m = -1;
			else
				m = 1;
			
			Explosion.p[i].angle = -angle + m * tb_Rnd(0,10);
		}	// End of if (999 > angle)
		else
		{
			Explosion.p[i].angle = tb_Rnd(0, 360);
		}
		
		f = (float)tb_Rnd(80, 100) / 100.0f;
		Explosion.p[i].life		= tb_Round(life * f);
		Explosion.p[i].r		= 255;
		Explosion.p[i].g		= 255;
		Explosion.p[i].b		= 255;
		Explosion.p[i].time		= 0;
		Explosion.p[i].Active	= TRUE;
		Explosion.p[i].gravity	= gravity;
		
		Explosion.p[i].vx		= Explosion.p[i].vi * cos(Explosion.p[i].angle * PI / 180.0f);
		Explosion.p[i].vy		= Explosion.p[i].vi * sin(Explosion.p[i].angle * PI / 180.0f);
	}	// End of for (i = 0; i < _MAXPARTICLES; i ++)
}

BOOL DrawParticleExplosion(HDC hdc)
{
	int			i;
	BOOL		finished = TRUE;
	float		r;				// 生命经过的百分比
	COLORREF	clr;
	
	if (Explosion.Active)
	{
		for (i = 0; i < _MAXPARTICLES; i ++)
		{
			if (Explosion.p[i].Active)
			{
				finished = FALSE;
				r = ((float)(Explosion.p[i].life - Explosion.p[i].time) / (float)(Explosion.p[i].life));
				
				// 计算粒子的颜色
				clr = RGB(tb_Round(r * Explosion.p[i].r), tb_Round(r * Explosion.p[i].g), tb_Round(r * Explosion.p[i].b));
				
				DrawCircle(
					hdc,
					Explosion.x + tb_Round(Explosion.p[i].x),
					Explosion.y + tb_Round(Explosion.p[i].y),
					2,	// 半径
					clr
					);
				Explosion.p[i].Active = UpdateParticleState(&(Explosion.p[i]), 10);
			}	// End of if (Explosion.p[i].Active)
		}	// End of for (i = 0; i < _MAXPARTICLES; i ++)
	}	// End of if (Explosion.Active)
	
	if (finished)
		// 如果所有粒子都死亡
	{
		Explosion.Active	= FALSE;
	}
	
	return !finished;
}

//********************************
//更新粒子属性,如运动时间,位置等
//********************************
BOOL	UpdateParticleState(TParticle* p, int dtime)
{
	BOOL	retval;
	float	t;
	
	p->time		+= dtime;
	
	if ((p->time) >= (p->life))
	{
		retval	= FALSE;
	}
	else
	{
		retval	= TRUE;
		
		t	= (float)(p->time) / 1000.0f;
		
		p->x	= p->vx * t;
		p->y	= p->vy * t + (p->gravity * t * t) / 2.0f;
	}
	
	return	retval;
}

/*还应改确定窗口大小,粒子出了窗口就死亡*/

⌨️ 快捷键说明

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