MFC学习笔记之二(制作人物动画+人物移动+地图拖曳)

2023-10-25 07:00

本文主要是介绍MFC学习笔记之二(制作人物动画+人物移动+地图拖曳),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

(三)制作人物动画

1)首先得有个人物图,比如说带4个方向的,比如说每个方向有四种形态的。

这样的话就有16张图了(他们还得尺寸相同),于是把这16张图放到一张图上,例如,每排放面向同一个方向的四个。

于是,就出现了像下面这张图

 

2)人物图出现了,那么为了让他们有不同的动画,自然不能像之前那样用Draw()函数了,毕竟,之前那个Draw()函数,只能描述在某张图上的某个区域画图。于是,使用Draw()的重载函数,其参数是

Draw(画在哪个DC起始x坐标起始y坐标, 图的宽度图的高度, 源图的起始x坐标源图的起始y坐标源图截取的宽度, 源图截取的高度);

总的来说,可以参考BitBlt函数来理解。

①画在哪个DC,跟其他的一样,例如画在内存DC上,就跟之前一样,比如cacheDC;

②第2,3个参数,指你在这个DC上的哪里开始画。这个xy坐标指的相对于DC上加载的(比如说DC加载位图)左上顶点(例如DC上加载一个图,左上的顶点是0,0)的坐标。

③第4,5个参数指这个图画的有多大,例如80,80就是指从第2,3个坐标开始计算,往右80和往下80,于是形成了一个矩形区域,这张图就画在这个矩形区域之中;

④第6,7个参数指从源图(也就是调用这个Draw函数的对象)的哪里(起点坐标)开始复制,例如假如这张图是320x320,那么160,160就是指从这张图的中心开始复制(于是左上、右上、左下这三个部分就被忽视了);

⑤第8,9个参数指从源图的起点坐标圈出多大一片矩形区域进行复制。

总的来说,2~5个参数是从第一个参数提供的DC中圈出一片区域,这个区域是被绘制的区域。第6~9个参数是指从调用对象的图片中圈出一片区域,这个区域的图片就被复制到2~5个参数提供的那个区域之中。

如果后者比前者的像素,那么被复制的图片就会被按比例缩小,相反则放大,因此应保证其尽量是一致的。

 

3)既然Draw函数可以选择性的截取人物图的某一部分,那么我们就得想办法设置其截取符合我们需要的部分。于是,需要有参数来描述方向(决定选择第几行的),还要有参数决定帧数(决定选择该行的第几个)。

因为不同动作和方向,只需要改变截取的部分,而每部分大小相同,因此分别给一个参数,让其可以影响第6,7个参数即可(因为高度和宽度是固定的,所以8,9参数保持不变)。因此声明int frameint direct(前者影响行,后者影响列)。

假如图片中,每个人物图都是80x80的尺寸,于是调用1x1图是,6,7参数为0,0,调用1x2图,6,7参数为80,02x2图则为80,80。因此,给frame赋值,让其表示的数字可以为0,80,160,240,给direct赋值,让其在不同方向时表示的数字可以为0,80,160,240。

因此,可以设置在按下w时(向上),让direct的值为240(表示第4行),其他类推。设置每次按下按键,人物动作都不同(每次加80,当超过240则自动归0)。

然后,让directframe的值能分别影响第6,7个参数(即让第6个参数为frame,让第7个参数为direct)。

而给framedirect初始赋值,应在OnPaint()函数之前(否则会导致每次都给初始赋值),例如在PreCreateWindow()函数之中。

而修改frame和direct的值,应该在键盘响应函数或者鼠标响应函数或者计时器函数等中进行修改。

如:

<span style="font-size:14px;">void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{// TODO: 在此添加消息处理程序代码和/或调用默认值switch (nChar){case 'D':myHero.x += 10;    //向右移动10个像素的单位  myHero.direct = 2;	//修改方向m_client.left -= 30;	//让背景图移动m_client.right -= 30;	//让背景图移动
.......省略部分}myHero.frame++;	//修改帧数if (myHero.frame == 4)myHero.frame = 0;		//假如超出第4帧,则归0
}</span>

这里之所以用的20,是因为在Draw函数里,对其乘以80了,因此效果是一样的。


(四)人物的移动拖着大地图移动


<span style="font-size:14px;">	//以下是根据人物移动,拖着大地图显示部分走//往右if (myHero.x + m_client.left > 600 && m_client.left + m_client.Width() > 800)		//如果人物的坐标在屏幕上位于靠右的200宽度了m_client.left = 600 - myHero.x;//往下if (myHero.y + m_client.top > 400 && m_client.top + m_client.Height() > 600)m_client.top = 400 - myHero.y;//往左if (myHero.x + m_client.left < 200 && m_client.left < 0)		//如果人物的坐标在屏幕上位于靠右的200宽度了m_client.left = 200 - myHero.x;//往上if (myHero.y + m_client.top < 200 && m_client.top < 0)m_client.top = 200 - myHero.y;m_client.right = m_client.left + 1800;	//根据屏幕的最左边的坐标,调整最右边的m_client.bottom = m_client.top + 1448;	//根据屏幕最上面的坐标,调整最下面的,这里不能用Width()和Height()来调整(因为宽度和高度在减少),正常应该是固定尺寸的</span>

说明:

①显示范围800x600;

②当位于靠近边界200宽度的位置时,不移动。

③未设置禁止人物出边界的代码。

 

(五)在(四)的基础上,根据人物实际坐标导出人物在屏幕上的坐标

<span style="font-size:14px;">//根据人物的实际坐标、地图在DC上画画时的坐标,以及地图宽度,返回人物在屏幕上显示的坐标
int GetHeroX(int x, int mapx,int mapwidth)	//参数1是人物的实际x坐标(即相对于大地图左上部分的坐标),参数2是地图的x坐标,参数3是大地图的宽度,返回值是人物在屏幕上的坐标
{if (x < 200)return x;	//当小于200时,显示部分位于地图最左边并且不动else if (x>mapwidth - 200)return x - (mapwidth - 800);	//当大于地图宽度-200时,显示部分位于地图最右边并且不动,mapwidth-800是减去地图左边不显示的部分else return x + mapx;	//如果在中间,则坐标是人物的x坐标-地图的x左边(相对于地图开始显示部分的x坐标 的坐标)	
}
int GetHeroY(int y, int mapy, int mapheight)	//返回人物在屏幕上的y坐标
{if (y < 200)return y;	//当小于200时,显示部分位于地图最左边并且不动else if (y>mapheight - 200)return y - (mapheight - 600);	//当大于地图宽度-200时,显示部分位于地图最右边并且不动,mapwidth-800是减去地图左边不显示的部分else return y + mapy;	//如果在中间,则坐标是人物的x坐标-地图的x左边(相对于地图开始显示部分的x坐标 的坐标)	
}
</span>

为了搭配上面使用,还应调整在内存DCDraw函数的代码


<span style="font-size:14px;">m_bg.Draw(m_cacheDC, m_client);	//绘制背景图,代码保持不变(由于m_client变化了,因此实际绘制是有变化的)
myHero.m_hero.Draw(m_cacheDC, GetHeroX(myHero.x, m_client.left, m_client.Width()),GetHeroY(myHero.y, m_client.top, m_client.Height()), 80, 80,myHero.frame * 80, myHero.direct * 80, 80, 80);		//绘制英雄图,坐标是英雄,绘制到缓冲DC上</span>

第一个参数不变;

2,3个参数,调用函数,返回人物在DC上的坐标(跟背景图是独立的,但符合和背景图的相对坐标);

4,5个参数,表示绘制的矩形有多大(80x80);

后面都保持不变。

四和五的大概原理如下图



(六)设置一个Hero

用于控制人物的类,原理和上面其实是相同的,只是优化整合到一个类里面

<span style="font-size:14px;">class Hero
{int x;	//人物的x坐标(指左上部分)int y;//人物的y坐标(指左上部分)int frame;		//人物的帧数int direct;		//人物的方向
public:Hero(int X, int Y, int Frame, int Direct) :x(X), y(Y), frame(Frame), direct(Direct) {}	//默认构造函数CImage m_hero;	//人物图int& GetX() { return x; }	//获得X坐标,可以通过这个函数修改x坐标(直接赋值的形式)int&GetY() { return y; }int GetFrame() { return frame; }	//获得帧数,用于绘图时决定是哪一帧int& GetDirect() { return direct; }	//获得方向,用于绘图时决定是哪一个方向的图,鼠标直接指向时,需要通过其修改方向int GetHeroX(CRect &m_client);	//根据背景图和实际坐标,获得在DC上的坐标int GetHeroY(CRect &m_client);void addX(int X);	//增加参数位移(包含正负)void addY(int Y);void addFrame();	//帧数变换void SetClient(CRect &m_client);	//设置背景图在绘制时的坐标,人物移动拖动地图时使用
};#include "stdafx.h"
#include "ChildView.h"void Hero::addX(int X)
{x += X;    //向右移动10个像素的单位  if (X > 0)direct = 2;	//修改方向elsedirect = 1;
}
void Hero::addY(int Y)
{y += Y;    //向右移动10个像素的单位  if (Y > 0)direct = 0;	//修改方向elsedirect = 3;}
void Hero::addFrame()
{frame++;if (frame > 3)frame = 0;
}
void Hero::SetClient(CRect &m_client)	//注意,这里第二个参数是背景图的宽度
{if (x < 0)x = 0;if (y < 0)y = 0;if (x > m_client.Width() - 80)x = m_client.Width() - 80;if (y > m_client.Height() - 80)y = m_client.Height() - 80;int wi = m_client.Width();int he = m_client.Height();//往右if (x + m_client.left > 600 && m_client.left + m_client.Width() > 800)		//如果人物的坐标在屏幕上位于靠右的200宽度了m_client.left = 600 - x;//往左if (x + m_client.left < 200 && m_client.left < 0)		//如果人物的坐标在屏幕上位于靠右的200宽度了m_client.left = 200 - x;m_client.right = m_client.left + wi;	//根据屏幕的最左边的坐标,调整最右边的//往下if (y + m_client.top > 400 && m_client.top + m_client.Height() > 600)m_client.top = 400 - y;//往上if (y + m_client.top < 200 && m_client.top < 0)m_client.top = 200 - y;m_client.bottom = m_client.top + he;	//根据屏幕最上面的坐标,调整最下面的,这里不能用Width()和Height()来调整(因为宽度和高度在减少),正常应该是固定尺寸的
}
//根据人物的实际坐标、地图在DC上画画时的坐标,以及地图宽度,返回人物在屏幕上显示的坐标
int Hero::GetHeroX(CRect &m_client)	//参数1是人物的实际x坐标(即相对于大地图左上部分的坐标),参数2是地图的x坐标,参数3是大地图的宽度,返回值是人物在屏幕上的坐标
{if (x < 200)return x;	//当小于200时,显示部分位于地图最左边并且不动else if (x>m_client.Width() - 200)return x - (m_client.Width() - 800);	//当大于地图宽度-200时,显示部分位于地图最右边并且不动,mapwidth-800是减去地图左边不显示的部分else return x + m_client.left;	//如果在中间,则坐标是人物的x坐标-地图的x左边(相对于地图开始显示部分的x坐标 的坐标)	
}
int Hero::GetHeroY(CRect &m_client)	//返回人物在屏幕上的y坐标
{if (y < 200)return y;	//当小于200时,显示部分位于地图最左边并且不动else if (y>m_client.Height() - 200)return y - (m_client.Height() - 600);	//当大于地图宽度-200时,显示部分位于地图最右边并且不动,mapwidth-800是减去地图左边不显示的部分else return y + m_client.top;	//如果在中间,则坐标是人物的x坐标-地图的x左边(相对于地图开始显示部分的x坐标 的坐标)	
}
</span>


这篇关于MFC学习笔记之二(制作人物动画+人物移动+地图拖曳)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/qq20004604/article/details/50720205
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/280832

相关文章

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Kotlin Compose Button 实现长按监听并实现动画效果(完整代码)

《KotlinComposeButton实现长按监听并实现动画效果(完整代码)》想要实现长按按钮开始录音,松开发送的功能,因此为了实现这些功能就需要自己写一个Button来解决问题,下面小编给大... 目录Button 实现原理1. Surface 的作用(关键)2. InteractionSource3.

使用WPF实现窗口抖动动画效果

《使用WPF实现窗口抖动动画效果》在用户界面设计中,适当的动画反馈可以提升用户体验,尤其是在错误提示、操作失败等场景下,窗口抖动作为一种常见且直观的视觉反馈方式,常用于提醒用户注意当前状态,本文将详细... 目录前言实现思路概述核心代码实现1、 获取目标窗口2、初始化基础位置值3、创建抖动动画4、动画完成后

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

双系统电脑中把Ubuntu装进外接移动固态硬盘的全过程

《双系统电脑中把Ubuntu装进外接移动固态硬盘的全过程》:本文主要介绍如何在Windows11系统中使用VMware17创建虚拟机,并在虚拟机中安装Ubuntu22.04桌面版或Ubunt... 目录一、首先win11中安装vmware17二、磁盘分区三、保存四、使用虚拟机进行系统安装五、遇见的错误和解决