GMS2中滑鼠點擊後自動選擇最靠前的物體

【GameMaker Studio 2生肉教程】-【GMS2使用技巧合輯】-【原作者HeartBeast】 http://www.bilibili.com/video/av12056287/#page=3

大家好,今天來介紹一下HeartBeast的一個很實用的技巧教程——如何在GMS2中實現滑鼠點選畫面中的對象之後自動選中該對象。

最終效果則如下GIF圖所示:

首先我們需要創建對應的精靈文件,在這裡為了區分選中和未選中的不同狀態,我們給精靈設置兩幀稍有區別的畫面——純藍色塊代表未選中,然後加一圈白色邊框的作為選中狀態

然後我們用這個精靈創建一個對象,在Create事件中聲明兩個屬性:

selected = false ;image_speed = 0 ;

其中"selected"是我們的自定義變數,用這個變數來標識當前的對象是否被選中,默認為"false"未選中狀態。"image_speed"顯示為綠色我們可以明白這是GMS2的內置屬性變數,這是由於我們剛剛創建的精靈有兩幀圖像,這個速度是圖像的播放速度,我們設置為0意思是這個精靈不需要自動切換自己的畫面,固定在默認的畫面上即可。之後我們在該對象的"step"事件中再定義一個屬性:

image_index = selected ;

同樣我們看到又是綠色的內置屬性"image_index",這個屬性是用來設置當前的圖像使用精靈中的第幾幀圖像的,我們的精靈只有兩幀畫面,對應的序號是"0"和"1",而剛剛定義的"selected"變數也只有選中和未選中兩種狀態,對應的"true"和"false"也恰好等於"1"和"0",因此這句代碼就表示當前對象的畫面根據自身是否被選中的狀態自動切換畫面,就能從視覺上給予用戶選中和未選中的反饋效果了。接下來我們就要設置如何去切換選中狀態了,首先我們給對象創建一個滑鼠的點擊事件:

這裡我們選擇普通的左鍵點擊事件,這意味著滑鼠必須在對象範圍內點擊才會觸發該事件,這個事件中我們先加一行簡單的代碼:

selected = true ;

即當滑鼠在對象的畫面範圍內點擊時,將自定義變數"selected"設置為"true",即當前對象被選中,根據之前的代碼我們知道此時圖像會自動切換到序號為"1"的第二幀帶白色邊框的畫面上了,理論上似乎只要這樣就完成了滑鼠點擊和自動選中的工作,但我們實際測試一下遊戲會發現,這麼做並不完善。

當我們的對象相互疊加時,如果滑鼠點擊的區域恰好是幾個疊加對象的交集,那就會幾個對象同時切換到選中狀態,這很明顯是違背遊戲常識的,通常情況我們只會選中最靠近畫面前方的對象,被覆蓋在下方的對象是不會被選中的,因此我們需要再進行一些調整。

首先我們再創建一個新的對象,並且給這個新的對象添加一個全局的滑鼠左鍵點擊事件:

然後在這個事件中添加以下內容:

with (o_object){ selected = false ;}var instance = instance_postion(mouse_x,mouse_y,o_object);if instance_exists(instance) { instance.selected = true ;}

首先,這是一個全局的滑鼠左鍵單擊事件,意味著在遊戲畫面中每一次滑鼠點擊都可以觸發該事件,然後第一個"with(o_object)"代表這個事件需要聯動修改所有"o_object"對象所生成的實力,大括弧中的代碼表示,修改的是這些對象的選中狀態,全部修改為未選中狀態。然後我們用定義了一個臨時變數"instance",並且用"instance_potion()"的方法來檢測當前滑鼠點擊的區域內是否有"o_object"所生成的實例,如果有就把這個實例存到"instance"這個臨時變數中。最後在"if"語句中使用"instance_exists()"的方法判斷剛剛的臨時變數中是否已經存儲了實例,如果已經有實例了就將實例的選中狀態設置為選中狀態。這裡由於臨時變數被賦值只能賦一個實例,因此可以確保不會出現三個實例同時被選中的狀態,但是當我們把這個對象放進我們的遊戲場景中,然後測試遊戲時還是會發現可能出現問題——遊戲依然無法準確判斷對象的深度,可能誤選中靠後的實例。

這是因為在檢測是否有實例並且進行賦值時是根據實例的創建順序來判斷的,而中離畫面越深的實例其實越早被創建,因此在檢測時優先檢測到了靠後的對象

所以現在我們就知道我們該做什麼了,我們需要去判斷哪一個實例是比較靠前的,然後把最靠前的這個實例設置為選中狀態即可,但是GMS2中並沒有這種內置的方法可以實現這種判斷,所以我們需要自己來寫一個方法來實現這個功能,這需要我們新建一個"script"(腳本):

這個腳本我們命名為"top_instance_posion"即用來檢測最靠上的實例的方法,然後其中的方法我先貼出全文並簡單說明其中的思路:

///聲明當前腳本的傳入參數///@param x///@param y///@param objectvar xx = argument0 ;var yy = argument1 ;var object = argument2 ;

第一部分如注釋所說,是表明這個腳本允許被傳入些什麼參數的,這裡定義了三個參數,分別是x、y和object因為這個腳本是要用來檢測識別滑鼠點擊位置最頂層的對象實例的,所以最後這個方法將被用來判斷滑鼠所在的坐標位置是否有某個對象的實例,基本上是"instance_position()"的一個加強版。

//創建一個實例列表var instance_list = ds_list_create();

如果之前有看過翻譯的"ds_list"相關內容,這裡就能理解是建立了一個新的列表,這個列表在後面將用於保存檢測到的實例ID,因為滑鼠點擊的位置可能有多個實例,因此用一個列表來保存所有檢測到的實例。

//檢測第一個實例var instance = instance_postion(xx , yy , object) ;

這個方法其實昨天已經解釋過了,就是GMS2內置的用來檢測在某個坐標位置是否有某個特定對象的實例的方法,但是這個檢測是按照實例的創建順序來的,會默認返回最早創建的實例ID。

//創建一個最頂層實例的變數var top_instance = instance ;

這裡我們創建了一個臨時變數"top_instance"來保存剛剛我們獲取到的對應位置最早創建的那個實例ID

//循環檢測每一個實例,檢測深度屬性while instance_exists(instance){ ds_list_add(instance_list,instance); instance_deactive_object(instance); if instance.depth < top_instance.depth{ top_instance = instance ; } instance = instance_postion(xx,yy,object);}

這一段可以說就是這個腳本文件最關鍵的地方,第一行是一個while循環語句,條件是滑鼠點擊位置是否獲取到實例(如果沒有有效實例則不繼續觸發後續內容)。然後如果在對應位置確實有實例,首先把這個實例添加到剛剛創建的列表中保存。然後把剛剛檢測到的實例設置為未激活狀態,在這種狀態下之前的"instance_postion()"的方法就不再會檢測到這個實例,在檢測時會直接跳過去找之後創建的第一個實例。然後我們拿檢測到的實例的深度屬性和目前"top_instance"中保存的實例的深度屬性進行比較,一旦發現當前實例的深度屬性較小,那就意味著這個實例更靠近頂層,於是就把"top_instance"中保存的實例ID替換成當前這個更靠近頂層的實例ID。最後我們再次用"instance = instance_postion(xx,yy,object)"這個方法來檢測當前位置是否還有有效實例存在,如果有就會把實例ID保存到"instance"這個變數中,這跟第一句while語句相配合就會循環觸發這一整段的代碼,如果沒有就會跳過繼續執行後面的代碼。這一整段代碼的功能就是反覆檢測當前的位置是否有有效的實例,然後挨個檢測保存並設為非激活狀態,循環檢測直到當前位置所有的實例都被檢測一遍,並且從中找到深度屬性最小即最靠近頂部的那個實例ID保存到臨時變數"top_instance"中。

//重新激活所有的實例while ds_list_size(instance_list )> 0{ instance_active_object(instance_list[ | 0 ]); ds_list_delete(instance_list , 0);}

由於之前那個循環在檢測的過程中把所有的實例都變成了非激活狀態,為了後續我們能繼續正常使用這些對象因此需要把所有的實例重新激活,而我們之前每次檢測到的實例都保存到了列表中。因此我們又用了一個while循環,當列表中還有內容時,就把列表中第一個值對應的實例激活,然後把這個已經激活的值從列表中刪除,反覆操作直到列表中沒有任何內容為止。

//銷毀列表ds_list_destroy(instance_list);

為了節約內存的使用,在列表已經使用完畢沒有繼續使用的加之以後我們從內存中銷毀了這個列表。

//返回實例return top_instance ;

最後我們把"top_instance"中保存的最靠近頂部的那個實例ID返回

可以看到,我們定義了一個新的方法,這個方法在定義完成之後,使用起來是跟GMS2中的那些內置函數一樣的,我們只需要把原來那個檢測滑鼠點擊位置的實例的方法改成我們自己定義的「檢測所在位置最頂層實例」的這個方法即可。


推薦閱讀:

遊戲開發之伺服器技術選型淺析
翻譯-《彩虹六號:圍攻》中可破壞關卡中的動態音頻設計
大廠遊戲海外版出現私服用戶遭洗《劍俠情緣》等手游已中招
遊戲性能優化(1)-why & benchmark

TAG:GameMakerStudio | 遊戲開發 |