GameMaker|打方塊-04|球的移動|球的反彈

閱讀時間約 1 分鐘

這篇內容,主要會講解,關於球的相關設定,包括了如何讓玩家發球、如何讓球移動、如何讓球反彈、如何改變球的大小,等等的相關功能。

本篇教學所使用的系統是Windows 10,如果有按鍵相關的說明,會用Windows的系統來解釋。如果你用的是Mac系統,再麻煩自行換成相對應的按鍵。

raw-image


前置知識


在學習本篇內容之前,最好具備以下的前置知識,以免看不懂這篇教學的內容。


目標講解


本次的版本,會新增以下的功能:

  • 按A鍵,能讓遊戲暫停。
  • 按空白建,能改變球的大小。
  • 按Z/X/C鍵,能夠讓玩家發球。
  • 球在撞到牆壁或玩家時,會進行反彈。
  • 球在碰到out,或是飛出房間時,會自動銷毀。


另外,本次的版本,會出現以下的Bug:

  • 球會卡在玩家裡面。
  • 球會卡在牆壁裡面。
  • 不良的牆壁設定,會導致球穿牆。

由於篇幅的關係,Bug的部分,會留到下一篇的教學,再來講解處理方案。

範例版本展示

範例版本展示


事前準備


這邊要先請各位,準備一個寬高為80*80的矩形,以及一個直徑為160的圓形,尺寸的單位是pixel。

我個人是習慣使用PS,來製作2D素材,接著再導入專案當中。當然,你也可以使用Sprite的繪圖功能,來把素材製作出來。


設定暫停的變數


建立一個Script,將他命名成「scr_global_var」,這個腳本(Script)將會放置,所有的全域變數(Global Variable)。

在scr_global_var裡面,放入以下的程式碼:

//遊戲的狀態參數
global.game = {
//遊戲的播放狀態,0=暫停,1=遊戲中
play : 1 ,
}


這邊分享一個簡單的邏輯:「如果有兩個以上的物件,需要使用同一個變數,那就把這個變數,設定成全域變數。」

這個play的變數,不管是玩家、球、計時器,都會使用到,因此就需要把他,設定成全域變數。

scr_global_var的設定

scr_global_var的設定


這邊我使用了結構體(Struct)的資料型態(Data Type),來幫全域變數進行命名。

結構體的部分,我之前還沒講解過,各位可以把他理解成「資料夾」的功能,如果用上面的程式碼來解釋,game就是資料夾(結構體),而play就是資料夾裡面的變數。

由於目前只有這個變數,所以各位可能還無法理解,結構體的好處,等慢慢增加之後,會比較能理解結構體的用途。

這邊附上官方的說明書,之後如果有機會,我會在寫相關的教學:

結構體(官方的說明書)


設定out


建立一個Sprite,將他命名成「spr_out」,接著把80*80的素材匯入(Import)到spr_out裡面。

這個out的功能,是用來偵測球是否出界,如果觸碰到球,球就會被消除。

spr_out的設定,與spr_wall相同,一樣的碰撞遮罩,以及Nine Slice的設定。

spr_out的設定

spr_out的設定


建立一個Object,將他命名成「obj_out」,這表示out的物件。接著把Sprite的參數,設定成「spr_out」。

obj_out的設定

obj_out的設定


叫出rm_stage_01的房間,並在Instances的圖層上,建立out的實體,方法就跟牆壁一樣,放上去後拉長就行了。

建立out的實體

建立out的實體


設定球


建立一個Sprite,將他命名成「spr_ball_big」,接著把直徑為160的素材匯入到spr_ball_big裡面。

雖然說球有大中小三種尺寸,但在這個專案中,我們會透過改變圖片的Scale(縮放比例),來控制球的尺寸,因此這邊只需要準備,大球的尺寸即可。

碰撞遮罩需要把Type的參數,修改成Ellipse (Slow)。然後把Fps設定成0,確保這個Sprite不會產生動畫。

原點則是設定成Middle Centre,這表示物體的正中心。

spr_ball_big的設定

spr_ball_big的設定


建立一個Object,將他命名成「obj_ball」,這表示球的物件。接著把Sprite的參數,設定成「obj_ball」。

obj_ball的設定

obj_ball的設定


在obj_ball的物件裡,加入Create事件,並放入以下的程式碼:

//移動速度
move_speed = 30 ;

//設定移動速度
id.speed = move_speed ;


id.speed是內建變數(Built-in Variable),可以用來控制,實體的移動速度。

至於移動的方向,我們會透過玩家的物件,來進行控制,因此這邊不用加入。

設定obj_ball的Create事件

設定obj_ball的Create事件


除了移動速度之外,我們還需要改變球的大小,因此打開scr_global_var,放入以下的程式碼:

//球的參數
global.ball = {
//球的大小,"s"=小球,"n"=正常,"b"=大球
size : "n" ,
}


加入程式碼後的參考圖:

增加scr_global_var的變數

增加scr_global_var的變數


在obj_ball的Create事件裡,放入以下的程式碼:

//設定大小
if (global.ball.size == "n") {
id.image_xscale = 0.5 ;
id.image_yscale = 0.5 ;
} else if (global.ball.size == "b") {
id.image_xscale = 1 ;
id.image_yscale = 1 ;
} else if (global.ball.size == "s") {
id.image_xscale = 0.25 ;
id.image_yscale = 0.25 ;
}


在obj_ball的物件裡,加入Step事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
id.speed = move_speed ;
//設定大小
if (global.ball.size == "n") {
id.image_xscale = 0.5 ;
id.image_yscale = 0.5 ;
} else if (global.ball.size == "b") {
id.image_xscale = 1 ;
id.image_yscale = 1 ;
} else if (global.ball.size == "s") {
id.image_xscale = 0.25 ;
id.image_yscale = 0.25 ;
}
//除了遊戲中的狀態之外,其他狀態一律停止動作
} else {
id.speed = 0 ;
}


加入程式碼後的參考圖:


id.image_xscaleid.image_yscale是內建變數,可以用來改變,實體的圖片比例。

依照程式碼的設定,普通球("n")的直徑是80,大球("b")的直徑是160,小球("s")的直徑是40。

用來改變global.ball.size的程式碼,將會放在玩家的物件裡面。在玩家還沒改變大小的狀況下,應該會產生普通球,因為global.ball.size的初始值是"n"


補充說明一下,其實在Step事件裡面,撰寫改變大小的程式碼,並不是最優解,因為這樣每個step,都會去改變球的大小,如果球的數量太多,效能就會下降。

比較好的做法,應該是在「碰撞」到道具的時候,執行「一次性」的程式碼,來改變所有球的大小。

這邊是為了方便測試,所以才將他放在Step事件裡面。這在之後的版本中,會在進行修正。


接著要來設定,關於反彈的程式碼。

在obj_ball的物件裡,加入與obj_wall碰撞的事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
//微調反彈的角度,不然球的路徑,會一直保持不變
id.direction += irandom_range(-5 , 5) ;
//反彈
move_bounce_all(false) ;
}


在obj_ball的物件裡,加入與obj_player碰撞的事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
//微調反彈的角度,不然球的路徑,會一直保持不變
id.direction += irandom_range(-5 , 5) ;
//反彈
move_bounce_all(false) ;
}


加入程式碼後的參考圖:


當實體碰撞到實體時,就會觸發碰撞(Collision)事件。上面的設定,表示碰撞到obj_wall和obj_player時,就會觸發事件裡面的程式碼。


id.direction是內建變數,可以用來改變,實體的移動方向。irandom_range(-5 , 5)的用途,是隨機產生-5~5之間的整數。

id.direction += irandom_range(-5 , 5)的意思是:讓移動的方向,隨機加上-5~5的整數。

如果不加入這行程式碼,球依然能正常移動,只是路徑會變得「非常固定」,我個人覺得會有點無聊。

因此才加入這行程式碼,讓球路發生些微的改變,這樣遊戲的體驗,會變得更好一點。


呼叫move_bounce_all(false)的函式(Function),能讓球的移動路徑,變成反彈後的數值。講白話文就是讓球反彈。

接著要來設定,「讓球消失」的相關程式碼。


在obj_ball的物件裡,加入與obj_out碰撞的事件,並放入以下的程式碼:

//銷毀球
instance_destroy() ;


在obj_ball的物件裡,加入Outside Room事件,並放入以下的程式碼:

//防呆裝置,如果球還是不小心飛出房間(沒碰到out),那就自動銷毀
instance_destroy() ;


加入程式碼後的參考圖:


呼叫instance_destroy()的函式,能夠銷毀呼叫函式的實體,簡單來說就是自毀。

Outside Room的事件,會在實體超出房間後觸發。在「正常」的情況下,球應該只有在接觸到obj_out時,才會消失。

但為了防止意外的發生,所以才會在Outside Room的事件裡面,加入銷毀球的功能。


設定玩家


在obj_player的物件裡,加入Key Press - A事件,並放入以下的程式碼:

if (global.game.play == 0) {
global.game.play = 1 ;
} else if (global.game.play == 1) {
global.game.play = 0 ;
}


加入這段程式碼之後,我們就可以透過鍵盤上的A,來決定遊戲是否要暫停。

設定obj_player的Key Press - A事件

設定obj_player的Key Press - A事件


接著要修改一下,玩家移動的程式碼,把「暫停」的功能給加進去。

打開obj_player裡的Key Down - Left事件,並把程式碼,修改成以下的樣子:

//遊戲中
if (global.game.play == 1) {
//沒碰到牆就移動
if (!place_meeting(id.x - move_speed , id.y , obj_wall)) {
//往左移動move_speed的距離
id.x -= move_speed ;
} else {
//小於move_speed的距離,會出現隱形牆,把移動條件改成撞到牆為止
while (!place_meeting(id.x - 0.1 , id.y , obj_wall)) {
id.x -= 0.1 ;
}
}
}


打開obj_player裡的Key Down - Right事件,並把程式碼,修改成以下的樣子:

//遊戲中
if (global.game.play == 1) {
//沒碰到牆就移動
if (!place_meeting(id.x + move_speed , id.y , obj_wall)) {
//往右移動move_speed的距離
id.x += move_speed ;
} else {
//小於move_speed的距離,會出現隱形牆,把移動條件改成撞到牆為止
while (!place_meeting(id.x + 0.1 , id.y , obj_wall)) {
id.x += 0.1 ;
}
}
}


修改後的參考圖:


在obj_player的物件裡,加入Key Press - Space事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
//改變球的大小,變化的順序為小中大
if (global.ball.size == "n") {
global.ball.size = "b" ;
} else if (global.ball.size == "b") {
global.ball.size = "s" ;
} else if (global.ball.size == "s") {
global.ball.size = "n" ;
}
}


加入這段程式碼之後,我們就可以透過空白鍵,來改變球的大小。

設定obj_player的Key Press - Space事件

設定obj_player的Key Press - Space事件


在obj_player的物件裡,加入Key Press - Z事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
//用球的大小,來決定y座標的偏移量
var _move_y = 0 ;
if (global.ball.size == "n") {
_move_y = 80 ;
} else if (global.ball.size == "b") {
_move_y = 120 ;
} else if (global.ball.size == "s") {
_move_y = 80 ;
}
//向130~140度發球,單發射擊
var _ball = instance_create_depth(id.x , id.y - _move_y , 0 , obj_ball) ;
_ball.direction = 135 ;
_ball.direction += irandom_range(-5 , 5) ;
}


加入程式碼後的參考圖:

設定obj_player的Key Press - Z事件

設定obj_player的Key Press - Z事件


instance_create_depth(id.x , id.y - _move_y , 0 , obj_ball)的意思是:在座標(id.x , id.y-_move_y)的位置上,建立一個obj_ball的實體,深度設定為0。

這個函式在使用的時候,會順便回傳,這個新建實體的ID。因此,我們可以透過這種特性,來改變球的移動方向。

改變方向的方法很簡單,就是先建立一個局部變數(Local Variable):_ball,並把函式回傳的ID放入_ball

接著我們就可以透過_ball,來改變移動方向的參數,例如:_ball.direction = 135,就是把球的移動的方向,設定成135度。

(GameMaker是用移動方向的直線,與基準線的夾角,來表示實體的移動方向。0代表右側,90代表上方,180代表左側,270代表下方。)


_move_y的用途,是讓球生成的位置,變成在玩家的原點(Origin)上方。

原本是直接用120的數值,但後來發現,大球可以用120,但其他的兩個尺寸,用120的間距會太大,看起來並不合適。

因此才決定加入,偏移量的程式碼,讓大球的距離是120,剩下的兩個,則是使用80。


X鍵和C鍵的發球,跟Z鍵的邏輯是一樣的,只是做了一些微調。

X鍵的發射方向是40~50度,而C鍵則是連發模式,按著就能連續發射,發射的方向則是在45~135度之間。

下面是X鍵和C鍵的設定方法。


在obj_player的物件裡,加入Key Press - X事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
//用球的大小,來決定y座標的偏移量
var _move_y = 0 ;
if (global.ball.size == "n") {
_move_y = 80 ;
} else if (global.ball.size == "b") {
_move_y = 120 ;
} else if (global.ball.size == "s") {
_move_y = 80 ;
}
//向40~50度發球,單發射擊
var _ball = instance_create_depth(id.x , id.y - _move_y , 0 , obj_ball) ;
_ball.direction = 45 ;
_ball.direction += irandom_range(-5 , 5) ;
}


在obj_player的物件裡,加入Key Down - C事件,並放入以下的程式碼:

//遊戲中
if (global.game.play == 1) {
//用球的大小,來決定y座標的偏移量
var _move_y = 0 ;
if (global.ball.size == "n") {
_move_y = 80 ;
} else if (global.ball.size == "b") {
_move_y = 120 ;
} else if (global.ball.size == "s") {
_move_y = 80 ;
}
//向45~135度發球,連發射擊
var _ball = instance_create_depth(id.x , id.y - _move_y , 0 , obj_ball) ;
_ball.direction = 90 ;
_ball.direction += irandom_range(-45 , 45) ;
}


加入程式碼後的參考圖:


善心提醒,C鍵是使用「Key Down事件」,這樣子才可以按著連發,而用來單發的X鍵,則是使用Key Press事件,記得不要設定錯誤了。




🔔如果內容對你有幫助,可以按個喜歡,這樣就能讓更多人,接觸到這些棒棒的內容🔔


✨祝各位也能開心的做出好遊戲✨

免費、開心、簡單,這是我做教學的理念,我希望透過我的行動,讓人們找回自我學習的快樂,讓那些資源稀少的自學者們,也能朝著自己的夢想來前進。讓我們一起開心的做出遊戲吧!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
這篇內容,主要會講解,要如何規劃房間、相機,以及各種物件的尺寸大小。
這篇內容,主要會講解,如何讓玩家進行移動,在解釋的過程中,會接觸到碰撞遮罩、Nine Slice、鍵盤事件,等等的相關設定。
這是一篇前導文章,主要解釋「打方塊」的實戰範例,可以學習到哪方面的技巧,讀完之後,各位可以決定,要不要繼續學習這個專案。
這篇內容,介紹了知識傳遞的三種型態,以及GameMaker教學的分類方式。閱讀本篇指南,能夠理解GameMaker教學的整體規劃和知識結構。
這篇內容,主要會講解,要如何規劃房間、相機,以及各種物件的尺寸大小。
這篇內容,主要會講解,如何讓玩家進行移動,在解釋的過程中,會接觸到碰撞遮罩、Nine Slice、鍵盤事件,等等的相關設定。
這是一篇前導文章,主要解釋「打方塊」的實戰範例,可以學習到哪方面的技巧,讀完之後,各位可以決定,要不要繼續學習這個專案。
這篇內容,介紹了知識傳遞的三種型態,以及GameMaker教學的分類方式。閱讀本篇指南,能夠理解GameMaker教學的整體規劃和知識結構。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
圍棋攻擊裡一定要會的技巧,攻擊時與對手的棋子保持一點距離,但又不讓對手可以簡單的拆邊來尋找根據地,是高手很常使用的攻擊技能,注意⚠️攻擊時儘量不要去碰對方的棋子,不然說不定會被對手利用而適得其反呢~
Thumbnail
本篇介紹單人遊戲的核心架構與邏輯,涵蓋發牌、抽牌、出牌及遊戲結算等重要步驟。文章也詳細介紹了使用 socket.io 建立連線的過程,並說明如何利用 React Hooks 管理遊戲狀態,提及後端伺服器如何處理玩家加入房間的事件,並簡要介紹了房間資訊的管理,此文將分為多篇進一步介紹遊戲事件部分。
Thumbnail
24點數學遊戲是一款適合小朋友與想動動腦的朋友們的小遊戲,遊戲規則簡單易懂,可訓練邏輯能力。遊戲分為單人與多人模式,可以讓玩家自行挑戰高分或是與其他玩家競爭。算式中不同的數學符號會對應不同的加分機制。遊戲網站連結與專案 repo 也都提供在文章中。
Thumbnail
原版的官方規則導入記分機制,但因為計算過於繁複,所以一般遊玩時較少採用。本變體規則旨在還原原規則的策略性,並保留平常的遊玩樂趣。 1. 配件準備 4枚不同顏色的棋子(紅、藍、黃、綠),以及一張標記0~15的場地。 2. 記分方式 一開始所有棋子都在0的位置。每一局結束時,贏家以外的所有人拿出
Thumbnail
1.不要讓棋譜或棋書擋到棋盤,視野可以看到完整的棋盤。 2.可以將佈局階段角落的變化背起來,之後進階背30手、50手,訓練記憶力。 3.有時可以猜猜看高手會下在哪個範圍,準確度慢慢提高,大局觀也會慢慢養成哦!
圍棋,是一種古老棋類遊戲,兩位玩家輪流在棋盤上放置黑白兩色的圓形石子,目標是在棋盤上形成多個區域,以擴大自己的領地並同時圍堵對手的石子。儘管規則簡單,但卻擁有極其豐富的戰術和戰略,每一步都是挑戰與機遇的交錯。加入我們,一同探索、學習、成長,讓圍棋成為你生活中不可或缺的一部分!
讓你的大腦像火箭一樣起飛!在我們的課程中,你將發現圍棋的魔法,從掌握基本知識到制定複雜策略。   我們的老師將用有趣的教學方法來啟發你的創造力和決策能力。 快來加入我們的團隊,一起在圍棋的世界中尋找冒險和樂趣吧!
學習如何提升子效,不浪費每一手棋的價值,透過精妙的佈局,不僅拓展你的棋界視野,更能在對局中一展長才⚫️⚪️
Thumbnail
建立幾個變數如下,最上面兩個變數值為清單值 接下來分別設定球1位置到左上角落、設定球2位置到右上角落、設定球3位置到左下角落、設定球4位置到右下角落 當螢幕初始化的時候,設定玩家球的X、Y座標和大小,並將玩家球的初始顏色,設定成(變數_顏色清單)中.....
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
圍棋攻擊裡一定要會的技巧,攻擊時與對手的棋子保持一點距離,但又不讓對手可以簡單的拆邊來尋找根據地,是高手很常使用的攻擊技能,注意⚠️攻擊時儘量不要去碰對方的棋子,不然說不定會被對手利用而適得其反呢~
Thumbnail
本篇介紹單人遊戲的核心架構與邏輯,涵蓋發牌、抽牌、出牌及遊戲結算等重要步驟。文章也詳細介紹了使用 socket.io 建立連線的過程,並說明如何利用 React Hooks 管理遊戲狀態,提及後端伺服器如何處理玩家加入房間的事件,並簡要介紹了房間資訊的管理,此文將分為多篇進一步介紹遊戲事件部分。
Thumbnail
24點數學遊戲是一款適合小朋友與想動動腦的朋友們的小遊戲,遊戲規則簡單易懂,可訓練邏輯能力。遊戲分為單人與多人模式,可以讓玩家自行挑戰高分或是與其他玩家競爭。算式中不同的數學符號會對應不同的加分機制。遊戲網站連結與專案 repo 也都提供在文章中。
Thumbnail
原版的官方規則導入記分機制,但因為計算過於繁複,所以一般遊玩時較少採用。本變體規則旨在還原原規則的策略性,並保留平常的遊玩樂趣。 1. 配件準備 4枚不同顏色的棋子(紅、藍、黃、綠),以及一張標記0~15的場地。 2. 記分方式 一開始所有棋子都在0的位置。每一局結束時,贏家以外的所有人拿出
Thumbnail
1.不要讓棋譜或棋書擋到棋盤,視野可以看到完整的棋盤。 2.可以將佈局階段角落的變化背起來,之後進階背30手、50手,訓練記憶力。 3.有時可以猜猜看高手會下在哪個範圍,準確度慢慢提高,大局觀也會慢慢養成哦!
圍棋,是一種古老棋類遊戲,兩位玩家輪流在棋盤上放置黑白兩色的圓形石子,目標是在棋盤上形成多個區域,以擴大自己的領地並同時圍堵對手的石子。儘管規則簡單,但卻擁有極其豐富的戰術和戰略,每一步都是挑戰與機遇的交錯。加入我們,一同探索、學習、成長,讓圍棋成為你生活中不可或缺的一部分!
讓你的大腦像火箭一樣起飛!在我們的課程中,你將發現圍棋的魔法,從掌握基本知識到制定複雜策略。   我們的老師將用有趣的教學方法來啟發你的創造力和決策能力。 快來加入我們的團隊,一起在圍棋的世界中尋找冒險和樂趣吧!
學習如何提升子效,不浪費每一手棋的價值,透過精妙的佈局,不僅拓展你的棋界視野,更能在對局中一展長才⚫️⚪️
Thumbnail
建立幾個變數如下,最上面兩個變數值為清單值 接下來分別設定球1位置到左上角落、設定球2位置到右上角落、設定球3位置到左下角落、設定球4位置到右下角落 當螢幕初始化的時候,設定玩家球的X、Y座標和大小,並將玩家球的初始顏色,設定成(變數_顏色清單)中.....