พัฒนาเกมบน iOS (iPhone/iPod/iPad) ตอนที่ 5 การใส่เสียงพื้นหลังและเสียงเอฟเฟค

บทความนี้เป็นบทความที่ตีพิมพ์ในนิตยสาร Pantip Guide ฉบับที่ 54 (ม.ค. – มี.ค.) โดยเป็นการสอนพัฒนาเกมบนระบบปฏิบัติการ iOS (iPhone / iPod / iPad) ซึ่งในตอนนี้จะอธิบายกล่าวถึงการใส่เสียงพื้นหลังและเสียงเอฟเฟค

 

สำหรับในบทความตอนนี้ผมจะเขียนถึงการใส่เสียงพื้นหลังและเสียงเอฟเฟค ซึ่งนับว่าเป็นสิ่งสำคัญอีกอย่างหนึ่งในการทำเกม ถ้ามีเพลงประกอบไพเราะน่าฟังและมีเสียงเอฟเฟคที่สมจริง ก็จะทำให้ผู้เล่นรู้สึกมีอารมณ์ร่วมไปกับเกมมากขึ้น

ในการทำเกมที่สร้างด้วย cocos2d-iphone ไฟล์เสียงที่รองรับมี 3 แบบ คือ CAF, AIF และ WAV เท่านั้น โดยส่วนใหญ่มักนิยมให้ CAF เนื่องจากขนาดไฟล์เล็ก แต่หลายคนอาจจะคุ้นเคยกับไฟล์ WAV มากกว่า ไม่เป็นไรครับ เราสามารถแปลงไฟล์ง่ายๆ โดยการใช้คำสั่ง afconvert ใน Terminal

 

ขั้นตอนการแปลงไฟล์เริ่มจากเปิดโปรแกรม Terminal ขึ้นมา หากใครไม่รู้ว่าอยู่ตรงไหน ก็ไปที่ Applications > Utilities > Terminal จากนั้นพิมพ์คำสั่งสำหรับแปลงไฟล์โดยมีรูปแบบ ดังนี้

 

afconvert –d [out data format] –f [out file format] [in file] [out file]

 

 

ตัวอย่างเช่น

 

afconvert –d LEI16 –f ‘caff’ bgsound.wav newbgsound.caf

 

หรือหากต้องการเปลี่ยน bit rate ก็สามารถทำได้ ด้วยคำสั่ง

afconvert –d aac –f ‘caff’ –b 131072 bgsound.caf newbgsound_128.caf (สำหรับ 128 บิต)
afconvert –d aac –f ‘caff’ –b 32786 bgsound.caf newbgsound_32.caf (สำหรับ 32 บิต)

 

ขั้นตอนต่อไปเป็นการเตรียมปุ่มสำหรับควบคุมเสียง ซึ่งในตัวอย่างต่อไปนี้จะมีปุ่มควบคุมเสียงจำนวน 2 ปุ่ม คือปุ่มสำหรับควบคุมเสียงพื้นหลัง และปุ่มสำหรับควบคุมเสียงเอฟเฟค ดังรูปที่ 1 โดยจะมีรูปที่ปล่อยไว้ปกติ กับรูปที่แสดงผลตอนใช้นิ้วทัช

 


รูปที่ 1 กราฟิกปุ่มสำหรับควบคุมเสียง

 

จากนั้นเริ่มต้นด้วยการสร้างโปรเจคใหม่ชื่อ iOSGame05 และนำรูปทั้ง 4 รูป เข้าไปในโฟวเดอร์ Resources ดังรูปที่ 2-3

 


รูปที่ 2 สร้างโปรเจคใหม่ชื่อ iOSGame05

 


รูปที่ 3 นำรูปเข้าในโฟวเดอร์ Resource

 

จากนั้นเขียนคำสั่งเพื่อประกาศตัวแปร _label, _bgSoundOnItem และ _bgSoundOffItem ซึ่งจะใช้เก็บข้อความแสดงผล ไอเทมสำหรับปุ่มเปิดเสียง และไอเทมสำหรับปุ่มปิดเสียง ตามลำดับ โดยเขียนลงในไฟล์ HelloWorldLayer.h ดังนี้

 

@interface HelloWorldLayer : CCLayer
{
    CCLabelTTF *_label;
    CCMenuItem *_bgSoundOnItem; 
    CCMenuItem *_bgSoundOffItem; 
}

 

จากนั้นเพิ่มคำสั่งสำหรับแสดงข้อความ คำสั่งสำหรับแสดงปุ่มที่เอาไว้ควบคุมการเล่นเสียงเอฟเฟค และคำสั่งสำหรับแสดงปุ่มที่เอาไว้ควบคุมการเล่นเสียงพื้นหลัง โดยเขียนไว้ในเมธอด init ที่อยู่ในไฟล์ HelloWorldLayer.m ดังนี้

 

-(id) init
{
	if( (self=[super init])) {
		
		_label = [CCLabelTTF labelWithString:@"Status: BGSound On" fontName:@"Marker Felt" fontSize:32];
		CGSize size = [[CCDirector sharedDirector] winSize];
		_label.position =  ccp( size.width /2 , size.height - (_label.contentSize.height/2) );
		[self addChild: _label];
        
        
        		CCMenuItem *fxsdMenuItem = [CCMenuItemImage itemFromNormalImage:@"fxsd1.png" selectedImage:@"fxsd2.png" target:self selector:@selector(fxsdButtonTapped:)];
        		fxsdMenuItem.position = ccp(150, 200);
        		CCMenu *fxsdMenu = [CCMenu menuWithItems:fxsdMenuItem, nil];
        		fxsdMenu.position = CGPointZero;
        		[self addChild:fxsdMenu];
        
        
        		_bgSoundOffItem = [[CCMenuItemImage itemFromNormalImage:@"bgsd1.png" selectedImage:@"bgsd1.png" target:nil selector:nil] retain];
        		_bgSoundOnItem = [[CCMenuItemImage itemFromNormalImage:@"bgsd2.png" selectedImage:@"bgsd2.png" target:nil selector:nil] retain];
        		CCMenuItemToggle *toggleItem = [CCMenuItemToggle itemWithTarget:self selector:@selector(bgSoundOnOffButtonTapped:) items:_bgSoundOnItem, _bgSoundOffItem, nil];
        		CCMenu *toggleMenu = [CCMenu menuWithItems:toggleItem, nil];
        		toggleMenu.position = ccp(250, 200);
        		[self addChild:toggleMenu];

	}
	return self;
}

 

จากข้างต้นจะเห็นว่าในแต่ละปุ่มจะมีรูป 2 รูป คือรูปที่แสดงผลปกติ และรูปที่แสดงผลเมื่อคลิ๊กปุ่มหรือทัชที่ปุ่ม
ต่อไปเพิ่มเมธอด fxsdButtonTapped ซึ่งเป็นเมธอดสำหรับให้ทำงานเมื่อกดปุ่มเล่นเสียงเอฟเฟค โดยในเบื้องต้นเมื่อกดปุ่มก็จะให้แสดงข้อความด้านบนเป็น Status: SoundFX On ดังนี้

 

- (void)fxsdButtonTapped:(id)sender {
    [_label setString:@"Status: SoundFX On"];
}

 

เพิ่มเมธอด bgSoundOnOffButtonTapped ซึ่งเป็นเมธอดสำหรับให้ทำงานเมื่อกดปุ่มเล่นเสียงพื้นหลัง ดังนี้

 

- (void)bgSoundOnOffButtonTapped:(id)sender {
    CCMenuItemToggle *toggleItem = (CCMenuItemToggle *)sender;
    if (toggleItem.selectedItem == _bgSoundOffItem) {
        [_label setString:@"Status: BGSound Off"];
        [[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
    } else if (toggleItem.selectedItem == _bgSoundOnItem) {
        [_label setString:@"Status: BGSound On"];
  }
    
}

 

เมื่อดูแล้วไม่มีข้อผิดพลาดใดๆ ก็รันคำสั่งได้เลย ซึ่งจะได้ผลลัพธ์ดังรูปที่ 4

 


รูปที่ 4 แสดงผลปุ่มกดสำหรับควบคุมเสียง

 

เมื่อเราลองกดปุ่มทั้งสองปุ่มจะเห็นว่าแตกต่างการโดยแบบแรกเอาไว้สำหรับเล่นเสียงเอฟเฟค การทำงานของปุ่มคือเมื่อเรากดจะเปลี่ยนเป็นอีกรูป และเมื่อปล่อยจะกลับเป็นรูปเดิม ซึ่งปุ่มแบบนี้จะใช้คลาส CCMenuItem ส่วนปุ่มสำหรับควบคุมเสียงพื้นหลังการทำงานของปุ่มจะเปลี่ยนรูปเมื่อเรากดแล้วปล่อย และเมื่อกดแล้วปล่อยอีกครั้งก็จะเปลี่ยนเป็นรูปเดิม วนแบบนี้ไปเรื่อยๆ ซึ่งปุ่มแบบนี้จะใช้คลาส CCMenuItemToggle
เมื่อเราได้ปุ่มสำหรับควบคุมเสียงเรียบร้อยแล้ว ขั้นตอนต่อไปเป็นการนำเสียงเข้ามาโดยนำเข้ามาโปรเจค โดยในตัวอย่างนี้มี 2 ไฟล์คือ bgsound.caf และ fxsound.caf ดังรูปที่ 5

 


รูปที่ 5 นำไฟล์เสียงเข้าในโปรเจค

 

สำหรับการเล่นเสียงใน cocos2d-iphone มีคลาสสำเร็จรูปมาให้เราใช้ โดยคลาสที่ใช้สำหรับเล่นเสียงคือคลาส SimpleAudioEngine ซึ่งเรา import เข้ามาด้วยคำสั่ง

 

#import "SimpleAudioEngine.h"

 

 

เพิ่มคำสั่งเพื่อให้เปิดมาแล้วเล่นเสียงเลย ดังนี้

-(id) init
{
	…        
        
        [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"bgSound.caf"];
	}
	return self;
}

เพิ่มคำสั่งเมื่อกดปุ่มให้เล่นเสียงตามที่กำหนด โดยถ้าต้องการเล่นเสียงเอฟเฟคที่เล่นครั้งเดียวจะใช้คำสั่ง playEffect แต่ถ้าต้องการเล่นเสียงพื้นหลังที่วนลูปไปเรื่อยๆ จะใช้คำสั่ง playBackgroundMusic ดังนี้

- (void)fxsdButtonTapped:(id)sender {
    
    [_label setString:@"Status: SoundFX On"];
    [[SimpleAudioEngine sharedEngine] playEffect:@"fxSound.caf"];
}

- (void)bgSoundOnOffButtonTapped:(id)sender {
    
    CCMenuItemToggle *toggleItem = (CCMenuItemToggle *)sender;
    if (toggleItem.selectedItem == _bgSoundOffItem) {
        [_label setString:@"Status: BGSound Off"];
        [[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
    } else if (toggleItem.selectedItem == _bgSoundOnItem) {
        [_label setString:@"Status: BGSound On"];
        [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"bgSound.caf"];
    }
    
}

 

ปิดท้ายด้วยการเขียนคำสั่งเพื่อคืนหน่วยความจำ ดังนี้

 

- (void) dealloc
{
	[_label release];
    	_label = nil;
    	[_bgSoundOffItem release];
    	_bgSoundOffItem = nil;
    	[_bgSoundOnItem release];
    	_bgSoundOnItem = nil;

	[super dealloc];
}

 

เป็นอันเสร็จเรียนร้อย ถ้าไม่มีอะไรผิดพลาดเมื่อเรากดรัน ก็จะมีเสียงพื้นหลังเริ่มเล่นและเล่นวนลูปไปเรื่อยๆ และถ้ากดปุ่มเล่นเสียงเอฟเฟคก็จะเล่นเสียงเอฟเฟคออกมา โดยเราสามารถกดได้ด้วยความถี่บ่อยๆ ได้
จากบทความข้างต้นนี้ถ้าใครมีเกมอยู่แล้วจากบทความที่ผ่านๆ มา ก็ลองนำเสียงเข้าไปในเกม ก็จะทำให้เกมเราดูสนุกมากขึ้น ลองดูนะครับ!

 

มนตรี อินทโชติ

 

Leave a Reply