SFML中双击鼠标左键会双击如何实现

  1. 基本的方法来检查键盘、鼠标的狀态
  2. 理解并运行不同类型的事件
  3. 设计并实现一个事件管理器

1.基本的方法来检查键盘、鼠标的状态

前面的几章已经稍微涉及了检索外围输出嘚主题
而且,具有讽刺意味的是这个类的整个范围都被覆盖了。
来确定某个键盘键的实时状态
这个键作为参数传递给方法,由sf::Keyboard::Key枚举表表示
因为这个方法是静态的,所以sf::Keyboard不需要实例化
这是我们在前几章中检查输入的方式,
但是如果我们想要检查更多的击键,
它确實会带来一些if/else语句的混乱

简单理解一下,我们前面看到的"isKeyPressed()"这个函数基本上可以代表整个keyboard类的用法了
相当简单有点类似于Java swing中的listening概念,因为是静态方法所以不需要实例化也可以直接使用。
但是有一个坏处就是可能我们需要一堆if-else语句来判断这可能会使我们的整个程序看起来
不知道有没有办法使用Switch case 来优化。

可以预见的是SFML还提供了一个类似于sf::Keyboard的类,
其思想与获取鼠标的实时状态相同:sf:: mouse
很像它的合作伙伴,键盘它提供了一种方式来检查鼠标按钮被按下,
鼠标类提供了它自己的枚举任何鼠标上可能的按钮我们总共有5个:

简单解释:基本上哃上Keyboard。都是用"列举"比较容易理解
就是想吐槽一下,这个XButton1、2是游戏鼠标么?

此外,sf::Mouse类提供了一种获取和设置当前鼠标位置的方法:
这两個方法都有一个重载的版本该版本接受对窗口的引用,
以便确定是查看相对于窗口的鼠标坐标还是相对于桌面的鼠标坐标
如果没有提供对窗口的引用,就像前面示例的第1行一样
那么返回的鼠标位置就是从桌面原点到鼠标所在位置的距离。
但是如果提供了对窗口的引鼡,那么位置就是窗口原点和鼠标位置之间的距离
换句话说,示例#2中的鼠标位置是相对于窗口的
同样的逻辑也适用于第3行和第4行,只昰鼠标的位置被设置为提供的int vector参数

这点的意思就是,可以用上述代码获取当前鼠标位置加window参数的获取的是相对应用窗口位置,不加则昰相对于desktop的鼠标位置
同样setposition的话给一组向量用来设置,后面的windows参数同理

关于函数的重载(overload),可以回忆一下指的是函数名相同,而函数参數不同从而构成了不同的函数签名

在这里指的就是加或者不加window这个参数。

是的正如标题所述,SFML不仅支持来自键盘和鼠标的输入
还支歭来自连接到计算机的其他外围设备的输入。
通过使用只包含静态方法的类sf::Joystick就像前面两个类一样,
可以检查控制器(controller)是否连接检查其按鈕状态,甚至确定控制器是否支持某些轴上的位置

健身环大冒险???
可以支持除了鼠标、键盘以外的其他外围输入
好像关于作業处理,谁都可以成为成外围(大雾)
这里是指控制器与设备的链接?接下来是通过控制器来检测状态

SFML最多支持同时连接8个不同的控淛器,这些控制器由[0;7]范围内的数值索引标识
因此,sf::Joystick提供的每个方法都必须至少有一个参数也就是控制器ID。
如果我们有一个ID为0的控制器我们可以检查它实际支持多少个按钮,如下所示:
因为没有其他方法可以抽象地定义地球上每个控制器的按钮
所以它们只是通过0到31之间嘚数字索引来引用。
检查按钮按钮可以通过调用isButtonPressed()方法来完成如下所示:

这里我有点懵,尝试着理解一共31个按键在电脑上,这个"isButtonPressed"很明显两個参数中第一个是指的控制器,第二个指的是Button id

为了检查一个控制器是否支持一个特定的轴,我们可以使用hasAxis()方法:
sf::Joystick::Axis封装枚举了控制器可能支持的所有轴因此可以按照前面的代码进行检查。
假设控制器支持它则其当前沿轴位置的获取方法如下:
前面的方法将返回控制器0上X轴囷Y轴的当前位置。

说实话我还是不太理解控制器。是指这个控制器与某一(或几个)外围设备相连以后直接通过控制器访问外围设备狀态么?这里获取坐标可以理解为当其与鼠标相连接以后,获取鼠标的position么

tips: 因为sf::Joystick状态是在检查事件时更新的,所以在事件有机会轮询之湔使用这些方法时可能会出现一些问题如果是这种情况,最好手动调用sf::Joystick:Update()方法以确保您拥有最新的外围设备状态。

2.理解并运行不同类型嘚事件

再次强调sf::Event是我们简单提到过的东西,
但是如果我们想要构建一个能够无缝处理所有类型的事件而不出现任何问题的系统,
那么必须在继续之前对其进行扩展并更好地理解它
首先,让我们重申一下什么是Event
SF:Event是一个Union,在c++术语意味着它是一个特殊的类只可容纳一个非静態数据成员,
SizeEvent,他持有的信息为我们窗口经过重新调整尺寸以后的大小,和其他信息。
由于sf::Event的这种性质如果新来者以错误的方式处理事件,
那麼它可能成为一个陷阱
因为union的所有成员共享相同的内存空间,(这点关于Union数据结构可以查一下菜鸟)
所以这会导致未定义的行为并会導致应用程序崩溃,
除非您知道自己在做什么(否则别瞎几把访问Event)

这里的意思是不要尝试着去访问Event的内容,通常情况下都会出bug
但问题是,我不去读取我怎么知道是啥?
所以下面做的是根据情况排除将不确定消减到最小以后,再去访问
(存疑,我理解的可能有问题)

讓我们来看看处理事件最基本的方式:
没有什么是我们以前没有见过的
尽管我们填补了正在发生的事情的空白是很重要的。
根据其类型咜将选择union中的一个结构作为active data structure来携带与事件相关的数据。
然后我们可以检查事件的类型,
并确保使用正确的data member来获得所需的信息
例如,如果事件类型是sf:: event::Closed那么代码将导致未定义的行为。
只有当延迟生效以后Event 才会被调度,然后再次被调度
当你按下一个键并按住它时,首先咜只显示一个字符
这与此事件的工作方式完全相同。
对于任何需要在键被按住的情况下保持连续的操作使用它甚至都不是最优的,
以便检查键的实际状态
同样的思想也适用于鼠标和控制器的输入。
对于每次击键只需要发生一次的事情来说
使用这些事件是非常理想的,

简单理解一下原理他解释了半天,我也没懂就是说KeyPressed相当于打栓狙,摁一下打一下很合适。
搞到自动步枪上就会产生很奇妙的延遲(也许吧)

 虽然这种方法在小型项目中是可管理的,与之前的输入示例几乎相同但是它在更大的范围内可能很快就会失控。让我们面對现实吧(这意味着要学更多滑稽),处理每个输入设备的所有事件、击键和状态就像我们在前一个项目中所做的那样,简直是一场噩梦(我的上帝啊我要用靴子狠狠地踢你的屁股)。还不相信吗?想象一下在一个应用程序中,您希望检查同时按下的多个键并在这些键同时按下时调用某个函数。不太糟糕?让我们在这个场景中包含事件为了调用一个函数,您需要检查同时按下的两个键和正在发生的某个事件这又增加了一层复杂性,但是没有什么是你不能处理的对吧?在其中加入一些布尔标志来跟踪事件状态或者也许击键不应该太難。

想想一个大跳牵扯到好几重事件判断,混合到一起产生了新的事件。
这个单单用机械的判断组合是很难做到的或者说做到了也昰很混乱的。

随着时间的推移应用程序现在需要
你可以构建它,但是添加新功能或扩展那些堆积如山的废话将会非常尴尬
以至于您很鈳能会放弃它。(写JAVA小游戏时进行的动作判断)
为什么要把你自己放到如此sb的境界,
而不是付出少许努力、构架出一个自动解决过程(automated approach)
可以加載任何组合键和事件从一个文件,
并且仍然保持代码一样整洁(neat and clean),如果没有更多要求的话
让我们通过开发一个能够处理所有这些问题的系统(system)来聰明地解决这个问题。

虽然没看懂但好像很聪明的鸭子。

清晰我们的需求是我们需要做的第一件也是最关键的一件事在我们整个设计过程中(自动开启软件设计模式)覆盖所有需求是非常困难的然而忘了某一个特性,可能会导致后续所有的代码结构或者构架改变说到這儿了,让我们现在来列出我们对事件管理器的需求列表 
  • 如果满足绑定的所有条件(例如按下键、单击双击鼠标左键会或失去焦点的窗口),则将上述功能绑定到将调用的方法
  • 可以通过事件管理器实际解决被轮询的SFML events
  • 从配置文件加载绑定(所以游戏一般都有配置文件)
现在我们已经搞到需求了让我们开始设计吧!我们需要用到 EventManager.h这个文件来包含除了类定义之外的所有细节。我们首先要定义的是所有我们将要处理的Event type(枚举出来)这可以在以后进行扩展,
但是由于它将非常适合我们现在的目的所以现在还不需要担心它。让我们写枚举表:

上述事件大多數都是真实(actual)事件;
但是请注意终止枚举之前的最后一行。
我们正在设置我们自己的事件
所有枚举本质上都是指向整数值的关键字,
所以最后一行可以防止任何类型的标识符冲突
并确保在该点之后添加的任何内容都高于绝对最大值sf::Event::EventType枚举值。
只要最后一行之前添加的内嫆是有效的事件类型就不应该有冲突。

我个人是这样子理解的前面设置了多少事前,最后这个count可以理解为是一个函数看之前一共有哆少event,python中有类似的操作用来算tuple中有多少元素。
至于加一则可能是用于数组防止越界(仅代表个人猜测,有问题欢迎大家斧正)
最后這个keyboard,我们照着他的写就好所有事件写到他前面,最后count+1赋值给keyBoard一下用keyboard来做边界。

接下来让我们去存储这些对应于绑定的事件组
我们現在知道,为了绑定一个key,我们需要事件类型和我们想要的key对应的code一些事件我们只需要存储它的类型。这意味着我们只需简单的存储一個整数0对于这些类型。
知道这些以后我们一起来定义一个新的struct来帮助我们存储这些信息:

翻译到这里真的是吐血,这里我也没怎么看懂可以直接看书74页,如果还是没看懂就跟着我抹黑看下去吧。

接下来让我们为每个绑定存储这些事件组。我们知道为了绑定到键,峩们需要事件类型和我们感兴趣的键的代码我们将处理的一些事件只需要存储类型,在这种情况下我们可以简单地用类型存储整数值0。知道了这一点让我们定义一个新的结构来帮助我们存储这些信息:

因为我们将需要分享event 信息给使用这个类的代码,
现在是一个好时机去創建一个数据类型帮助我们去这样做:

: m_name(l_bindName)//说实话我c艹学的不好这个函数后面带个冒号又来一个函数我是真的没懂

构造函数获取我们希望将事件绑定到的操作的名称,(lname)
并使用初始化器列表设置类数据成员
它只是获取一个事件类型和一个事件信息结构,
以便将其添加到事件向量Φ
一个额外的数据成员,我们之前没有提到名字的整数c。
根据注释,这个变量跟踪实际发生的事件的数量,
这将会帮助之后确定所有keys和events绑定关系是“打开”着的

说实话上面的我没看懂c++搞的有点头大。只是看关键词中有说到利用初始化器列表来初始化class data member 然而这个实际操作跟我搜箌的不一样啊大兄弟。。
这些列出来的struct我也不知道怎么用,真的是卡在这里了

在我们的绑定中使用std::unordered_map可以保证每个操作只有一个绑定,
因为它是一个关联容器而操作名称字符串是该容器的键。

没有顺序的映射键值为操作符名称。这相当于typedef了

下面讲的这段话基本上紦之前的解释了。

到目前为止我们做得很好,
但是如果没有一种方法可以将这些操作绑定到将被调用的有效方法上,这个系统是相当無用的
我们来讨论一下如何实现它。
在计算机科学的世界里你可能经常听到“回调”这个词。
简单地说回调是作为参数传递给另一段代码的代码块,它将在方便的时候执行它
在我们的事件管理器中,方便的时间是当绑定到特定操作的所有事件发生时
回调是表示正茬执行的操作的方法。
比方说我们想让角色在空格键被点击时跳跃。
我们将创建一个名为“Jump”的绑定(这是我们的操作名)并向其添加一個KeyDown类型的事件和代码sf::Keyboard::Space。
为了方便讨论假设字符有一个名为Jump()的方法。
我们希望将该方法绑定到名称“Jump”并让事件管理器在按下空格键时調用角色的Jump()方法。
简而言之这就是我们用这个新系统处理输入的方式。

到目前为止你的c++背景可能正在引导您使用术语“函数指针”。(回调函数需要函数指针调用)
虽然这并不一定是一个坏的选择但如果你是新手,它可能会变得有点混乱(是一定的)
这种方法的主要问題是将类的方法添加为回调的场景。
指向类成员的指针与常规函数并不完全相同除非它是静态方法。
下面是一个成员函数指针的基本定義:

这就好多了至少我们现在可以调用这个方法,尽管我们仍然被限制为只有一个类
我们可以在“SomeClass”类的方法中封装其他所有类方法调鼡,但这很乏味而且更重要的是,这是一个糟糕的实践
也许现在您认为一些模板魔术可以解决这个问题。
虽然这是可能的但您也必須考虑到兼容性和它可能造成的混乱。
考虑这可能需要的最少量的努力:

这本身并不能解决任何问题反而会带来更多的问题。
首先您现茬必须在事件管理器类中定义该模板,这是有问题的
因为我们需要一个容器来处理所有这些回调,
这意味着必须对整个事件管理器类进荇模板化这将其锁定为一个类类型。
使用typedef将是一个聪明的想法
除了它在大多数Visual Studio编译器中不支持这种形式:

对于非c++ 11编译器有一些笨拙的变通方法,
比如在定义模板后在结构体中包装typedef
然而,这也不能解决我们的问题
在使用“模板化”成员函数指针类型定义时,Visual Studio 2010编译器甚至會崩溃
这是相当混乱的,此时您可能正在考虑简单地返回到常规函数指针并将每个成员函数调用包装到不同的函数中。
不用担心c++ 11引叺了一个比这更好的方法

这里解释一下,其实上面的没有直接分章就直接开始讲回调函数了我这里是手动分开了回调函数讲解。然后上媔那个template可以类比Java中的泛型理解我也不知道这么理解对不对。还是建议大家多查资料限于本人水平,整篇下来会有不少矛盾点还是希朢大家有问题都能扔到群里。也是帮我改正错误谢谢!

在本例中,我们实例化了一个名为“foo”的函数包装器它包含一个带有void(void)签名的函數。
在等号的右边我们使用std::bind将类“Bar”的成员函数“method1”绑定到foo对象。
第二个参数因为这是一个成员函数指针,是类的实例该类的方法紸册为回调。
在本例中它必须是Bar类的一个实例,所以让我们假设这行代码是在它的实现中编写的然后传入“this”。
现在我们的foo对象被绑萣到类Bar的方法method1
因为std::函数重载了括号操作符,所以调用它就像这样简单:

如果需要可以稍后更改。

此时我们已经拥有了实际编写事件管悝器类头部所需的一切。
考虑到我们之前所做的所有设计决策结果应该如下所示:

从类定义中可以看出,我们仍然需要为AddCallback()方法使用templated成员函數指针参数
但是,std::function的使用将其独立为单个方法
这意味着我们不必对整个类进行template,
在指向方法和类实例的指针以及一个占位符(将来会被┅个参数替换)被绑定到一个临时函数之后
我们将它插入回调容器。
为了保持一致性而且因为它是一个非常简单的方法,所以我们也在頭文件中定义了RemoveCallback()

关于header的另一件值得指出的事情是将用于获取鼠标位置的方法的实现:GetMousePos()。
以防我们希望返回的坐标是相对于特定窗口的
同樣的窗口也可能有焦点或者失去焦点,所以一个m_hasFocus标记被保留以跟踪它

在这种情况下,构造函数的工作非常简单
该方法用于从文件中加載关于绑定的信息。

析构函数的工作对于这类class来说也很普通
如果你还记得,我们将绑定存储在堆上
因此必须取消对这个动态内存的分配。

如您所见它接受一个指向绑定的指针。然后检查绑定容器是否已经有了同名的绑定
如果是,则该方法返回false这对于错误检查非常囿用。
如果没有名称冲突则将新绑定插入到容器中。

我们有一种添加绑定的方法但是如何删除它们呢?

它接受一个字符串参数,并在容器中搜索要存储到迭代器中的匹配项
如果找到匹配项,它首先通过删除键-值对中的第二个元素(为绑定对象分配的动态内存)来释放内存
嘫后在返回true之前,擦除容器中的条目。

正如在设计该类的规范中所提到的我们需要一种方法来处理在每个迭代中轮询的SFML事件,
以便查看它們并查看其中是否有我们感兴趣的内容

//不是说好了不去访问事件内部的么?小老弟

它适当地接收类型为sf::Event的参数。
然后该方法必须遍历所有绑定并通过绑定内的每个事件来检查l_event参数的类型是否与当前正在处理的绑定事件的类型相匹配
如果是,我们将检查它是键盘事件还昰鼠标事件
因为这涉及到进一步检查键盘键或鼠标按钮是否匹配所需的绑定。
如果是其中之一最后一步是检查键盘键代码或鼠标按钮玳码,
匹配我们绑定事件的代码
在这种情况下,或者如果它是一个不同类型的事件,不需要进一步的处理。
因只显示几行下来,我们只需增加綁定实例的成员c来表示匹配在相关事件信息已经被存储在绑定的事件信息结构中以后的很短时间内。

我们再次遍历所有绑定及其事件
嘫而,在这种情况下我们只对键盘、鼠标和操纵杆感兴趣,
因为这些是我们能够检查实时输入的唯一设备
与前面类似,我们检查正在處理的事件类型并使用适当的类检查输入。
像往常一样增加绑定类的c成员是我们注册匹配项的方法。

最后一步是检查事件容器中的事件数量是否与“on”的事件数量匹配
如果匹配,我们在m_callbacks容器中找到回调
并使用parenthesis操作符调用第二个数据成员,
因为它是一个std::function方法包装器嘫后正式实现回调。
我们将包含所有事件信息的EventDetails结构的地址传递给它
然后,为下一次迭代将活动事件计数器c重置为0是很重要的
因为之湔检查的任何事件的状态都可能已经更改,并且它们都需要重新计算

最后,如果您从头到尾地查看代码您可能会注意到控制器输入的凊况并没有起任何作用。
事实上我们甚至不处理任何与控制器相关的事件。
这是以后可以扩展的东西对我们的任何项目都不是至关重偠的。
如果您渴望添加对操纵杆的支持并能够使用操纵杆请将其视为本章之后的作业。

它可以被格式成任何你想要的格式
然而,为了簡单起见它的布局在这里仍然是非常基本的。
每一行都是一个新的绑定
它以绑定名称开始,然后是事件类型枚举的数字表示和冒号分隔的事件代码
每个不同的事件 key:value pair由空格、绑定名称和事件开头分隔。

我们首先尝试打开keys.cfg文件
如果它失败了,这个方法会弹出一个控制台消息通知我们
接下来,我们进入一个while循环以便读取文件中的每一行。
我们定义了一个std::stringstream对象它允许我们使用>>操作符一片片地“流”字苻串。

它使用空间的默认分隔符这就是为什么我们要为配置文件做出这样的决定。
在获得绑定的名称之后我们创建一个新的绑定实例,并在构造函数中传递该名称
然后,通过进入while循环并使用!keystream.eof()作为参数我们确保它循环,直到std::stringstream对象到达它正在读取的行尾
及其重载的>>操莋符,缺省情况下使用空白作为分隔符

//都是在解释这个读取配置文档并把它实现的细节操作,可以看成是string操作练习课

在流式传输事件的類型和代码之后我们必须确保将其从字符串转换为两个整数值,
然后将它们存储在各自的局部变量中它接受前面读入的部分字符串,
鉯便通过在分隔符字符处拆分键:值对来分隔它们
在本例中,分隔符在这个方法的最顶层定义为“:”
如果在字符串中没有找到该字符,綁定实例将被删除行将被跳过,
因为它很可能没有正确格式化
如果不是这样,则成功地绑定事件并将代码转移到下一对

一旦所有的徝都被读入并到达行尾,
我们就尝试将绑定添加到事件管理器中
这是在if语句中完成的,目的是捕获我们前面谈到的与绑定名称冲突相关嘚错误
如果存在冲突,则删除绑定实例

您可能已经知道,在使用后关闭文件也很重要
所以这是我们在这个方法结束之前做的最后一件事。
完成这些之后我们的事件管理器就完成了,是时候实际地将其投入工作了

除了添加用于获取事件管理器的额外方法外,
还修改叻全屏toggle方法
一个Close方法也被添加到我们的窗口类中,
以及一个标记来跟踪窗口是否在焦点中
关闭窗口的方法很简单,只需设置一个标志為真:

这将确保在窗口中分派的每个事件都将得到适当的处理
如果窗口的焦点发生变化,它也会通知事件管理器

是时候实际使用事件管悝器了!
注册两个回调到一些成员函数,
在创建事件管理器的新实例之后:

让我们返回到keys.cfg文件
它本质上分解为KeyDown的事件类型(数字5)和键盘上F5键的玳码(数字89)。
这两个值都是我们使用的枚举的整数表示

设置的另一个回调是针对Window_close操作的,该操作在配置文件中绑定为0:0
事件类型0对应于枚舉表中的Closed,代码是不相关的因此我们也将其设置为0。

这两个操作都会绑定到Window类的方法
注意AddCallback方法中的最后一个参数,它是一个指向窗口當前实例的指针
在成功编译和启动之后,您应该会发现按下键盘上的F5键会切换窗口的全屏模式,然后单击close按钮实际上会关闭窗口
现茬让我们做一些更有趣的事情。

现在我们有了一个棒棒的事件管理器
让我们通过在按住左shift键并按下双击鼠标左键会时将一个精灵移动到鼠标的位置来完整地测试
如前几章所述设置它们。
出于我们的目的我们将只重用前几章中的蘑菇图形。
现在在你的游戏类中添加并实现┅个名为MoveSprite的新方法:

我们在这里要做的是从事件管理器中获取鼠标相对于当前窗口的位置
并将其存储在名为mousepos的本地整数向量中。
然后我們将sprite的位置设置为当前鼠标位置,并在控制台窗口中打印出一个小句子
非常基础,但它可以很好地用作测试让我们设置我们的回调:

并潒之前一样传递一个指向当前实例的指针。
在运行这个之前让我们先看看在keys.cfg文件中定义移动操作的方式:

它是双击鼠标左键会被按下的事件。
第二个事件类型对应于键盘事件

在编译和执行应用程序之后,我们应该在屏幕上呈现一个人物
如果我们按住左shift键左键点击屏幕上嘚任何地方,它会神奇地移动到那个位置!

即使在这种设计中知道何时使用哪种类型的事件也是很重要的。
例如对于涉及左移和R键的绑萣,您只希望回调被调用一次
您不会将这两种事件类型都定义为键盘,因为只要这些键按下就会一直调用回调方法。
您也不希望将这兩个事件都定义为KeyDown事件因为这意味着必须同时注册这两个事件,
而当按住多个键时由于屏幕刷新速度的原因,很可能不会发生这种情況
正确的使用方法是将KeyBoard和KeyDown事件混合使用,
这样最后按下的键就是KeyDown类型其余的键都是键盘类型。
在我们的示例中这意味着我们将通过sf::Keyboard類检查左shift键,
这可能听起来很奇怪但是,考虑一下计算机上著名的Ctrl + Alt + Del组合键的例子>它是这样工作的,但是如果你按相反的顺序拿着钥匙
它什么也不会做。如果我们正在实现这个功能
而通过事件轮询注册Del键。

关于该类的使用需要注意的最后一点是,有些事件还不受支歭
因为要充分利用它们需要额外的信息,这些信息是从sf::Event类获得的
当我们处理需要这些事件的问题时,
将在后面的章节中讨论事件管理器的适当扩展以支持这些特性

新手在使用SFML输入时最常犯的一个错误是使用某些方法检查用户input for wrong tasks,
理解你所使用的任何东西的局限性是培养任何一种像样的性能的关键
为了获得最佳的结果,请确保坚持我们所讨论的所有不同机制的预期用途

人们常犯的另一个错误是在.cpp文件Φ而不是在头文件中定义模板。
如果你出现了连接错误,用于修饰或说明一种方法利用模板,
确保将方法的实现和模板的声明放入头文件中

朂后,很多SFML的新用户都犯了一个非常简单但又非常流行的错误
那就是不知道如何正确获取窗口的相对鼠标坐标。
犯错的范围从简单地使鼡错误的坐标和体验怪异的行为到抓取相对于桌面的坐标以及窗口的位置并从另一个减去一个以获得本地鼠标位置。
虽然后一种方法可荇但是有点过分,特别是因为SFML已经为您提供了一种无需重新发明轮子的方法

扯了这么多,就是没讲event manager 实现的解释说明。难道这很简單么???

总结总个屁结,我累死了

此讲义是根据《游戏课程设计》李老师的课堂代码所写的设计过程讲义。
主要对游戏整体框架进行拆解和分析

  1. 场景,雷按钮的基本布置。
  2. 双击鼠标左键会单击可以翻开所选块面
  3. 鼠标右键单击可以插旗标记所选块面为雷。
  4. 双击鼠标左键会双击可以检测所选的块面周围一圈是否已经查找出所有雷

根據渲染驱动游戏的思想,可以得到以下主循环

主循环主要分为初始化,输入逻辑判断,输出

初始化 难度以及布尔变量

其中IniData()和LoadMediaData()分别初始化雷的二维排列数组,提前载入贴图素材

在输入的同时,实际集成了反馈左键单击双击右键单击的响应事件。

 

LButtonDown()LButtonDblClk(),RButtonDown()分别代表鼠标的三种操作以及触发的事件左键单击和双击之间的区别是时间间隔。

一个小程序:图片代替鼠标移动

当鼠标移动到窗口内鼠标不见了,取而代之的是图片.....

发布了0 篇原创文章 · 获赞 10 · 访问量 7万+

我要回帖

更多关于 双击鼠标左键会 的文章

 

随机推荐