当前位置: 首页 > news >正文

Win32_3Bitmap位图应用2 ------ 键盘控制人物走动

今天掌握了Bitmap的用法,忍不住再来一次升级版的应用------用键盘控制人物的走动,这个可能在游戏设计中用的很多,不过今儿就先来小试牛刀,呵呵……

本人学习编程有个"癖好" —— 那就是有了想法,下一步就是实现,越快实现越好,不实现就誓不罢休……

好了,F话少说了,还是先来逐步了解需求吧

(1)首先需要一个完整的人物走路分解图,每一个方向4张,分别是:直立、右脚向前、直立、左脚向前

(资源由本人亲自制作,待会儿上传^_^)

(2)加载位图到内存中,这个和Bitmap应用1一样,不再赘述

(3)获取位图ID

首先需要写两个方法:

IDB_BITMAP GetBitmapID(int dir, int dirCount);					//获取当前绘制的位图ID
void DrawBitmap(HINSTANCE, HDC, int, int, int, int);	//绘制位图
(IDB_BITMAP就是int)

本程序总共需要16张位图,位图ID是从101开始,每一张是紧挨着的(101~116),所以可以通过ID这个特点来控制位图的选择

GetBitmapID()的参数dir取以下4个之1:(位图的排列顺序为: 前后左右)

//位图的方位
#define DIR_FRONT	0
#define DIR_REAR	1
#define DIR_LEFT	2
#define DIR_RIGHT	3

参数dirCount取以下4个之1(也就是方向键连续按下的次数,每次对4求余数,因为每一个方向有4张分解图)

static int		frontC, rearC, leftC, rightC;
//计数是为了控制每个方向所显示状态(立正、右脚向前、立正、左脚向前)

然后简单的运算就能得到相应的位图ID号:

101 + dir*4 + dirCount

(4)用键盘控制人物的走动

由于每一个方向的处理类似,这里就简述一下向前走的控制算法:

rearC=leftC=rightC=0;//清除

//控制移动的距离
if(!(frontC % 2))	//当人物直立时,移动距离控制为10
{
	y += 10;
}		
else		//当人物左脚或右脚向前时,移动距离控制为2   这是经过多次测试得到的数据,这样控制的效果较好
{
	y += 2;
}

DrawBitmap(hInstance, hdc, DIR_FRONT, frontC, x, y);//绘制人物的状态
frontC = (frontC+1) % 4;//计算本方向(如果继续按下Dowm键)的下一次移动

(5)清除上一步的状态,也就是将上一步的位图刷掉

方法还是调用BitBlt()方法,只不过是绘制一块白色的位图,仅仅需要将最后一个参数设定为WHITENESS就ok了

好了这就是全过程,以下就是完整代码:

//前后左右移动的小猫
#include<windows.h>
#include<stdio.h>
#include"resource.h"

//位图的方位
#define DIR_FRONT	0
#define DIR_REAR	1
#define DIR_LEFT	2
#define DIR_RIGHT	3

//类型的重定义
typedef int			IDB_BITMAP;

/**    为重绘保存上一步的信息    **/
//保存上一步的位图
BITMAP	lastBitmap;
//保存上一步位图的坐标
int		lastX, lastY;
//保存上一步位图的方向和按键计数
int		lastDir, lastDirCount;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
IDB_BITMAP GetBitmapID(int, int);						//获取当前绘制的位图ID
void DrawBitmap(HINSTANCE, HDC, int, int, int, int);	//绘制位图

int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
                   PSTR szCmdLine,
				   int iCmdShow)
{
	static	TCHAR	szAppName[] = TEXT("MoveCat");
	HWND			hwnd;
	MSG				msg;
	WNDCLASS		wndclass;
	
	wndclass.style			= CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= 0;
	wndclass.cbWndExtra		= 0;
	wndclass.hInstance		= hInstance;
	wndclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName	= NULL;
	wndclass.lpszClassName	= szAppName;
	
	if(!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}
	
	hwnd = CreateWindow(szAppName,
						TEXT("MoveCat Demo"),
						WS_OVERLAPPEDWINDOW,
						(1366 - 720) / 2,
						(768 - 570) / 2,
						720,
						570,
						NULL,
						NULL,
						hInstance,
						NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HINSTANCE	hInstance;//窗口的实例句柄
	static int			frontC, rearC, leftC, rightC, x, y;
	//分别表示方位键按键计数和位图显示的位置  计数是为了控制每个方向所显示状态(立正、右脚向前、立正、左脚向前)
	HDC					hdc;
	PAINTSTRUCT			ps;
	
	switch(message)
	{
	case WM_CREATE:
		hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
		return 0 ;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		if(lastBitmap.bmWidth)
		{
			DrawBitmap(hInstance, hdc, lastDir, lastDirCount, lastX, lastY);
		}
		else
		{
			DrawBitmap(hInstance, hdc, DIR_FRONT, frontC, x, y);
			frontC = (frontC + 1) % 4;
		}

		EndPaint(hwnd, &ps);
		return 0;

	//用键盘控制位图的显示
	case WM_KEYDOWN:
		hdc = GetDC(hwnd);

		switch(wParam)
		{
		//向前
		case VK_UP:
			frontC=leftC=rightC=0;//清空除当前方向的所有计数
			
			//控制移动的距离
			if(!(rearC % 2))
			{
				y -= 10;
			}
			else
			{
				y -= 2;
			}

			DrawBitmap(hInstance, hdc, DIR_REAR, rearC, x, y);
			rearC = (rearC+1) % 4;
			
			break;

		//向后
		case VK_DOWN:
			rearC=leftC=rightC=0;

			//控制移动的距离
			if(!(frontC % 2))
			{
				y += 10;
			}
			else
			{
				y += 2;
			}

			DrawBitmap(hInstance, hdc, DIR_FRONT, frontC, x, y);
			frontC = (frontC+1) % 4;

			break;

		//向左
		case VK_LEFT:
			frontC=rearC=rightC=0;

			//控制移动的距离
			if(!(leftC % 2))
			{
				x -= 15;
			}
			else
			{
				x -= 3;
			}

			DrawBitmap(hInstance, hdc, DIR_LEFT, leftC, x, y);			
			leftC = (leftC+1) % 4;
			
			break;

		//向右
		case VK_RIGHT:
			frontC=rearC=leftC=0;

			//控制移动的距离
			if(!(rightC % 2))
			{
				x += 15;
			}
			else
			{
				x += 3;
			}

			DrawBitmap(hInstance, hdc, DIR_RIGHT, rightC, x, y);
			rightC = (rightC+1) % 4;

			break;
		}
		ReleaseDC(hwnd, hdc);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}

IDB_BITMAP GetBitmapID(int dir, int dirCount)
{
	return 101 + dir*4 + dirCount;
}

//绘制位图
void DrawBitmap(HINSTANCE hInstance, HDC hdc, int dir, int dirCount, int x, int y)
{
	HBITMAP	hBitmap;
	BITMAP	bitmap;
	HDC		hdcMem;

	//用于创建和hdc兼容的内存设备控制表句柄  也就相当于在内存中绘图,一个缓冲(当然,位图也能支持"截图")
	hdcMem = CreateCompatibleDC(hdc);

	hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(GetBitmapID(dir, dirCount)));
	GetObject(hBitmap, sizeof(BITMAP), &bitmap);
	SelectObject(hdcMem, hBitmap);

	//清除上一步位图信息
	if(lastBitmap.bmWidth)
	{
		BitBlt(hdc, lastX - 1, lastY - 1, lastBitmap.bmWidth + 1, lastBitmap.bmHeight + 1, hdcMem, 0, 0, WHITENESS);
	}

	//保存上一步信息
	lastX = x;
	lastY = y;
	lastDir = dir;
	lastDirCount = dirCount;
	lastBitmap = bitmap;

	//绘制当前位图信息
	BitBlt(hdc, x, y, bitmap.bmWidth - 1, bitmap.bmHeight - 1, hdcMem, 0, 0, SRCCOPY);

	DeleteObject(hBitmap);
	DeleteDC(hdcMem);
}


运行效果:

点击下载位图资源

相关文章:

  • 布隆过滤器原理
  • C# 网络编程之最简单浏览器实现
  • Win32_4深入浅出Win32的计时器
  • response.IsClientConnected参考
  • 参数化SQL小认识
  • Win32_5程序员求爱的创意程序^_^
  • cisco单臂路由
  • VC2010中 调用DLL的方法
  • Win32_6Win32的验证码程序
  • iOS Xcode, 解决“Could not insert new outlet connection”的问题。
  • Win32_7由浅入深——滚动条
  • 简单实现web服务器负载均衡
  • Android编程之ActivityManager: Segmentation fault
  • C# 网络编程之网页简单下载实现
  • mac 下对 iterm 终端 设置代理
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 2017-08-04 前端日报
  • 2018一半小结一波
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • css选择器
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • HTML中设置input等文本框为不可操作
  • Laravel 中的一个后期静态绑定
  • leetcode46 Permutation 排列组合
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • opencv python Meanshift 和 Camshift
  • spring boot 整合mybatis 无法输出sql的问题
  • 搭建gitbook 和 访问权限认证
  • 给新手的新浪微博 SDK 集成教程【一】
  • 聊聊flink的TableFactory
  • 浅谈web中前端模板引擎的使用
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (09)Hive——CTE 公共表达式
  • (2)STM32单片机上位机
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (离散数学)逻辑连接词
  • (七)Java对象在Hibernate持久化层的状态
  • (三十五)大数据实战——Superset可视化平台搭建
  • (转)大型网站架构演变和知识体系
  • (转载)hibernate缓存
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .a文件和.so文件
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .net core 控制台应用程序读取配置文件app.config
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式