Sprite.
ต่อเนื่อจากโพสแรกที่ผ่านมา
สร้างเกมส์ง่ายๆ ด้วย C++ กับ Cocos2d-x ใน Visual Studio และ Eclipse

เรารู้วิธีสร้างโปรเจกต้นแบบไปแล้ว โพสนี้เราจะมาดู

  1. การใส่รูป (Sprite)
  2. Listener

ตัวอย่างเกมส์จริงที่ใช้ Cocos2d-x สร้าง

ครั้งนี้เราจะใช้ Eclipse เป็นตัวทำโปรเจกนะครับ ส่วนใครสะดวกจะใช้ VS ก็ไม่เป็นปัญหา

1.

สร้างคลาสขึ้นมาชื่อว่า GmaeScene.h และ GameScene.cpp

GmaeScene.h
{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
#ifndef GAMESCENE_H_
#define GAMESCENE_H_

class GameScene { public: GameScene(); virtual ~GameScene(); };

#endif /* GAMESCENE_H_ */

{/syntaxhighlighter}

GameScene.cpp
{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
#include "GameScene.h"

GameScene::GameScene() { // TODO Auto-generated constructor stub

}

GameScene::~GameScene() { // TODO Auto-generated destructor stub }

{/syntaxhighlighter}

ตอนนี้เราได้เตรียมคลาสไว้แล้ว ต่อไป เราจะไปหาภาพพื้นหลัง กับตัวละคร โพสนี้เราจะใช้แค่สองรูป
รูปที่ 1

รูปที่ 2

พอได้รูปทั้งสองแล้ว ก็ให้เอาไปไว้ที่โฟเดอร์ชื่อ Resources ดังรูป

จากรูป มีสิ่งที่น่าสนใจอยู่สองจุดคือ
  1. โฟเดอร์ Classes
  2. โฟเดอร์ Resources
    ในโฟเดอร์ classes นี่เราจะเก็บซอสโค๊ดของเราไว้ที่นี่ทั้งหมด อันที่เป็น C++ นะ ส่วนโฟเดอร์ Resources นี่ก็จะเก็บจำพวกรูปภาพ ไฟล์เสียง ไอคอน ฟอร์ต ต่างๆนา ไว้ที่นี้. ที่โปรเจกเขาวางโครงสร้างแบบนี้ก็เพื่อให้รองรับการคอมไพล์ได้หลายๆแพลตฟอร์ม เช่น Anroid,iOS และ Win32 เป็นต้น.

เมื่อเราได้รูปแล้ว ในที่นี้เราะเปลี่ยนชื่อไฟล์จาก 13526287812082.png ไปเป็น GameBackground.png
และ bug-308386_1280.png ไปเป็น Bug.png

ถึงเวลาโค๊คจริงๆละ

2.

อับเดท GameScene.h ให้เป็นตามแบบข้างล่าง

{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
#ifndef GAMESCENE_H_
#define GAMESCENE_H_
#include "cocos2d.h"
class GameScene: public cocos2d::Layer {
public:
	GameScene();
	virtual ~GameScene();
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC (GameScene);

};

#endif /* GAMESCENE_H_ */
{/syntaxhighlighter}

คุณสามารถเข้าไปดู CREATE_FUNC ได้ ถ้าคุณใช้ Eclipse สามารถก็ Ctrl ค้างไว้ แล้วคลิกไปที่ฟังก์มาโครตัวนั้น

3.

อับเดท GameScene.cpp ตามฟังก์ชั่นที่เราได้เพิ่มไว้ใน GameScene.h ดังต่อไปนี้

ก่อนอื่นเราต้องใช้คำสั่ง using namespace cocos2d; กันก่อน เพราะว่าเวลาเรียนกใช้คลาสต่างๆ จะได้ไม่ต้องระบุ cocos2d namespace ทุกครั้ง

{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
#include "GameScene.h"
USING_NS_CC;

{/syntaxhighlighter}

จากนั้น ก็ทำการสร้างฟังก์ชั่นที่เราปรากาศไว้ในไฟล์ header.

{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
Scene* GameScene::createScene()
{
    auto scene = Scene::create();
    auto layer = GameScene::create();
    scene->addChild(layer);
    return scene;
}

bool GameScene::init()
{
	if(!Layer::init())
	{
		return false;
	}


	return true;

}

{/syntaxhighlighter}
4.

ตอนนี้เราได้ Scene ใหม่แล้ว พร้อมที่จะใช้งานได้ แทนที่ HelloWorldScene.cpp เรียบร้อยแล้ว ว่าแต่ Scene นีที่นี้หมายถืงอะไร ไปดู

สำหรับ Cocos2d-x แล้ว Scene ก็เหมือนกับฉาก ฉากหนึ่ง. ในหนึ่งฉากนี้ เราสามารถใส่อะไรไปก็ได้ พอตากล้องมาถ่ายทำ เราก็จะเป็นตามเฉพาะที่ซีนนั้นๆได้จัดองค์ประกอบไว้ ซึ้งตอนนี้ GameScene.cpp ของเราเป็นซีนที่ว่างเปล่า ยังไม่มีอะไรทั้งนั้น นั้นก็แสดงว่าถ้า ผู้กำกับมาหันกล้องมาจับตรงนี้ มันก็จะมืดๆ ว่างเปล่า ไม่มีอะไรเลย

ณ ตอนนี้ ผู้กำกับ ( Director::getInstance(); ) กำลังถ่ายทำที่หน้า HelloWorld.cpp อยู่ แต่เราต้องการให้มาถ่ายที่ซีน GameScene.cpp ที่เราเตรียมไว้

5.

อับเดท AppDeligate.cpp ตามนี้

  1. เพิ่ม #include "GameScene.h" ต่อจาก #include "HelloWorldScene.h" ประมาณบรรทัดที่ 2
  2. ในฟังก์ชั่น bool AppDelegate::applicationDidFinishLaunching() ตรงบรรทัดก่อน return true; ให้เปลี่ยนตามนี้
{syntaxhighlighter brush:cpp;collapse:false;first-line:75}
//    auto scene = HelloWorld::createScene();
    auto scene = GameScene::createScene();

{/syntaxhighlighter}
6.

ถึงตอนนี้ ถ้าสมมุติว่าเราสร้างอะไรเสร็จหมดแล้ว เขียนโค๊ดอะไรเสร็จหมดแล้ว แต่ถ้าเวลาคอมไพล์จริงๆ Cocos2d-x จะไม่เห็นคลาสที่เราสร้างขึ้นมาใหม่ วิธีที่จะบอกให้ Cocos2d-x รู้ว่าต้องคอมไพล์ ไฟล์ไหนบ้าง ให้เข้าไปเพิ่มไฟล์ที่ต้องการจะให้คอมไพล์ได้ที่
/SpriteDemo/jni/Android.mk
ซึ่งเราก็จะเพิ่มได้ดังนี้

{syntaxhighlighter brush:cpp;collapse:false;first-line:1}

LOCAL_SRC_FILES := hellocpp/main.cpp ../../Classes/AppDelegate.cpp ../../Classes/HelloWorldScene.cpp ../../Classes/GameScene.cpp

{/syntaxhighlighter}

7.

ลองรันเกมส์นี้ดู ในที่นี้เราจะใช้ Android Emulator สำหรับการทดสอบ
เปิด command prompt ขึ้นมาไปที่โฟเดอร์โปรเจกที่เราสร้าง รันโดยใช้คอมมาน
cocos run –p android

พอรันเสร็จ เราก็จะเห็น scene เปล่าๆ ตามภาพ

8.

ถัดมา เราก็จะมาใส่ Backgroud กันก่อน เปิดไปที่ไฟล์ GameScene.cpp ตามนี้

{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
bool GameScene::init()
{
	if(!Layer::init())
	{
		return false;
	}
auto background = Sprite::create("GameBackground.png");
this->addChild(background);

return true;

}
{/syntaxhighlighter}

จากนั้นก็รันคอมมานด์เดิม cocos run –p android

9.

คุณก็จะเห็นว่า รูปขึ้น แต่มันไม่เต็มจอ และก็ไม่ตรงกลาง ดังนั้น เราต้งเซ็ตให้มันเต็มจอ และจัดตำแหน่งให้อยู่กึ่งกลาง

{syntaxhighlighter brush:cpp;collapse:false;first-line:1}
bool GameScene::init()
{
	if(!Layer::init())
	{
		return false;
	}
Sprite * background = Sprite::create("GameBackground.png");
this->addChild(background);

auto screenSize = Director::getInstance()->getVisibleSize();

background->setScaleX(screenSize.width / background->boundingBox().size.width );
background->setScaleY(screenSize.height / background->boundingBox().size.height );
background->setPosition(screenSize.width * 0.5f, screenSize.height * 0.5f);

return true;

}

{/syntaxhighlighter}

10.

แม้ว่าเราจะพยายาม ขยานขนาดรูปภาพ และจัดให้อยู่กึ่งกลางแล้ว แต่ว่าบางทีมันก็ยังไม่เต็มกรอบอยู่ดี ปัญหานี้แก้ได้โดยการตั้งกฏให้เกมส์ของเราขยายให้เต็มหน้าจอ ทำได้โดยเข้าไปแก้ไข ResolutionPolicy ในคลาส AppDelegate.cpp ในฟังก็ชั่น bool AppDelegate::applicationDidFinishLaunching()
ทำการเปลี่ยนจาก

{syntaxhighlighter brush:cpp;collapse:false;first-line:54}
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);

{/syntaxhighlighter}

ไปเป็น

{syntaxhighlighter brush:cpp;collapse:false;first-line:54}
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy:: EXACT_FIT);

{/syntaxhighlighter}

เราก็จะได้แบกกราวน์แสดงตามที่ต้องการแล้ว

11.

ต่อไป จากรูปแมลงที่เราเซฟมา เราจะกำหนดให้ว่า ถ้าคลิกตรงไหน ก็ให้แสดงรูป บั๊กนั้นตรงนั้น โค๊ดดังกล่าว สามารถทำได้เช่น

{syntaxhighlighter brush:cpp;collapse:false;first-line:29}
bool GameScene::init()
{
	if(!Layer::init())
	{
		return false;
	}

	auto * background = Sprite::create("GameBackground.png");
	this->addChild(background);

	auto screenSize = Director::getInstance()->getVisibleSize();

	background->setScaleX(screenSize.width / background->boundingBox().size.width );
	background->setScaleY(screenSize.height / background->boundingBox().size.height );
	background->setPosition(screenSize.width * 0.5f, screenSize.height * 0.5f);


	auto listener = EventListenerTouchOneByOne::create();
	listener->onTouchBegan = [&](Touch * touch, Event * event ){
		Sprite * bug = Sprite::create("Bug.png");
		bug->setPosition(touch->getLocation());
		this->addChild(bug);
		return true;
	};

	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);

	return true;

}

{/syntaxhighlighter}

บรรทัดที่ 46 auto listener = EventListenerTouchOneByOne::create(); คือการสร้าง listener มาอันหนึ่ง จากนั้นเราสร้างแลมดาขึ้นมาอีกอันหนึ่งไป assigned ให้กับ onTouchBegan

** หากคุณต้องการดูการใช้แลมดาอย่างคร่าวๆใน C++ สามาระดูได้ที่นี้ (ภาษาไทย )

ซึ้งแลมดานี้ไม่มีอะไรมาก ก็แค่สร้าง sprite ขึ้นมาอันหนึ่ง แล้วก็เซ็ตตำแหน่ง (แต่ยังไม่ได้เซตขนาด) ตามตำแหน่งที่เรากดๆ จิ้มๆ ลงไป จากนั้นก็วาดรูปแมลงใส่ในเลเยอร์นั้นๆ

บรรทัดที่ 54 เป็นการรีจิเตอร์ให้รู้ว่า this เนี้ยะจะทำการจับ event ที่ชื่อว่า listener ที่เราประกาศไว้

ก็จะได้ประมาณนี้

12.

ยินดีด้วยครับ คุณทำเสร็จแล้ว

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

Hiring! บริษัทที่น่าสนใจ

Carmen Software company cover
Carmen Software
Hotel Financial Solutions
Next Innovation (Thailand) Co., Ltd. company cover
Next Innovation (Thailand) Co., Ltd.
We are web design with consulting & engineering services driven the future stronger and flexibility.
KKP Dime company cover
KKP Dime
KKP Dime บริษัทในเครือเกียรตินาคินภัทร
Kiatnakin Phatra Financial Group company cover
Kiatnakin Phatra Financial Group
Financial Service
Fastwork Technologies company cover
Fastwork Technologies
Fastwork.co เว็บไซต์ที่รวบรวม ฟรีแลนซ์ มืออาชีพจากหลากหลายสายงานไว้ในที่เดียวกัน
Thoughtworks Thailand company cover
Thoughtworks Thailand
Thoughtworks เป็นบริษัทที่ปรึกษาด้านเทคโนโยลีระดับโลกที่คว้า Great Place to Work 3 ปีซ้อน
Iron Software company cover
Iron Software
Iron Software is an American company providing a suite of .NET libraries by engineer for engineers.
CLEVERSE company cover
CLEVERSE
Cleverse is a Venture Builder. Our team builds several tech companies.
Nipa Cloud company cover
Nipa Cloud
#1 OpenStack cloud provider in Thailand with our own data center and software platform.
Bangmod Enterprise company cover
Bangmod Enterprise
The leader in Cloud Server and Hosting in Thailand.
CIMB THAI Bank company cover
CIMB THAI Bank
MOVING FORWARD WITH YOU - CIMB is the leading ASEAN Bank
Bangkok Bank company cover
Bangkok Bank
Bangkok Bank is one of Southeast Asia's largest regional banks, a market leader in business banking
MuvMi (Urban Mobility Tech Co.,Ltd.) company cover
MuvMi (Urban Mobility Tech Co.,Ltd.)
Shape the future of urban mobility towards affordable, clean, and safe solutions
T.N. Digital Solution Co., Ltd. company cover
T.N. Digital Solution Co., Ltd.
TNDS has been involving in every first move of banking’s major digital transformation.
KBTG - KASIKORN Business-Technology Group company cover
KBTG - KASIKORN Business-Technology Group
KBTG - "The Technology Company for Digital Business Innovation"
Siam Commercial Bank Public Company Limited company cover
Siam Commercial Bank Public Company Limited
"Let's start a brighter career future together"
Icon Framework co.,Ltd. company cover
Icon Framework co.,Ltd.
Global Standard Platform for Real Estate แพลตฟอร์มสำหรับธุรกิจอสังหาริมทรัพย์ครบวงจร มาตรฐานระดับโลก
REFINITIV company cover
REFINITIV
The Financial and Risk business of Thomson Reuters is now Refinitiv
H LAB company cover
H LAB
Re-engineering healthcare systems through intelligent platforms and system design.
The Gang Technology Co., Ltd. company cover
The Gang Technology Co., Ltd.
We're a Digital Agency that helps our customers transform their business into digital with ease.
LTMH company cover
LTMH
LTMH มุ่งเน้นการพัฒนาผลิตภัณฑ์ที่สามารถช่วยพันธมิตรของเราให้บรรลุเป้าหมาย
Seven Peaks company cover
Seven Peaks
We Drive Digital Transformation
Wisesight (Thailand) Co., Ltd. company cover
Wisesight (Thailand) Co., Ltd.
The Best Choice For Handling Social Media · High Expertise in Social Data · Most Advanced and Secure
MOLOG Tech company cover
MOLOG Tech
We are Modern Logistic Platform, Specialize in WMS, OMS and TMS.
Data Wow Co.,Ltd company cover
Data Wow Co.,Ltd
We enable our clients to realize increased productivity by solving their most complex issues by Data
LINE Company Thailand company cover
LINE Company Thailand
LINE, the world's hottest mobile messaging platform, offers free text and voice messaging + Call
LINE MAN Wongnai company cover
LINE MAN Wongnai
Join our journey to becoming No.1 food platform in Thailand

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

ครับผม ตอนนี้ก็ทำงานเหมือนกัน จะมีก็แค่ช่วงเวลาว่างๆที่มีเพียงน้อยนิดในแต่ละสัปดาห์เอามาทำในสิ่งที่ทำแล้วมีความสุขครับ XNA ดูน่าสนใจดี แต่เหมือนตอนนี้เขาไม่พัฒนาต่อแล้วหรืออย่างไรครับ ?

เขาไม่ได้ไปต่อแล้วละครับ แต่มีคนเอามาเขียนใหม่หลายอันเช่น MonoGame, ANX, SharpDX... ที่นิยมกันก็เห็นจะเป็น MonoGame นะ แต่ทาง MS รู้สึกจะพลักให้ไปใช้ Unity เสียมากกว่าครับ

ส่วนตัวผมลอง Cocos แล้วไม่ค่อยชอบ รู้สึกว่ามันเยอะแยะตาแปะไก่เกินไป ผมก็เลยกลับไปใช้ SDL 2.0 เหมือนเดิม ได้ลงไปลุยโค๊ดระดับล่างสนุกกว่าน่ะครับ (แต่เข้าใจว่าถ้าทำแบบนั้นเยอะ ๆ แล้วเกมจะไม่เสร็จซะที)

เอาจริง ๆ คือ ที่ตอนนี้เขียนอยู่คือ Visual Novel ซึ่งจะใช้ฟีเจอร์ด้านตัวหนังสือประมาณนึง ปัญหาที่ผมเจอสำหรับ Cocos ก็คือการตัดบรรทัดใน Rich Text ซึ่งมันเพี้ยนไปเลย เพราะใน Rich Text มันจะประกอบด้วย Label ย่อย ๆ ถ้าเราใส่ \n ปุ๊บมันก็จะตัดใน Label ย่อย ๆ แทน (ผมแจ้งไปแล้วเรื่องนี้ น่าจะมีแก้ละ) และผมก็มีบอกอีกว่าสำหรับภาษาไทยเราใช้ manual break เยอะก็เลยจำเป็นต้องมี

แล้วก็ถ้าใช้ภาษาไทยก็จะเจอเรื่องวรรณยุกต์จม-วรรณยุกต์ลอย ซึ่งก็เพราะว่าตัว Text Layout Engine มันไม่ได้รองรับ Unicode Feature มากมายอะไร Kerning ก็ทำงานแปลก ๆ ผมมีเสนอให้เอา harfbuzz ที่เป็น opentype engine เสริมไปกับตัว freetype ที่เป็น font renderer ซึ่งจะมีข้อดีอีกอย่างคือลูกเล่นมันแพรวพราวมาก วาดตัวหนังสือแนวตั้งยังทำได้เลย (อันนี้เห็นคนจีน-ญี่ปุ่นสนใจอยู่)

พอเจออะไรเยอะ ๆ ผมก็เลยคิดว่าจะ implement ตัว rich text ของตัวเอง ปัญหาอีกอย่างที่เจอคือการเอา library อื่น ๆ เข้าไปใส่ในตัว Cocos นั้นค่อนข้างน่าปวดหัวเลย ... แล้วตัวมันเองก็ค่อนข้างใหญ่ ใช้ 3rd party เยอะ ผมก็เลยตัดใจย้อนกลับมา SDL2 ซึ่งมันอาจจะดูบ้านๆ ไปหน่อย แต่ผมก็ควบคุมอะไรเองได้แทบทุกอย่างครับ

ตอนนี้เพิ่ง implement ตัว label เสร็จ เดี๋ยวจะโดดไปเขียน Rich Text ซึ่งคงใช้เวลาไม่เยอะ น่าจะเป็นแนว ๆ เดียวกับที่ Cocos ใช้ครับ เขาออกแบบตัว api ได้โอเคเลยนะ

ผมเคยทำแนวๆ Visual Novel กับ XNA อยู่แต่ไม่ได้ใส่รายละเอียดเยอะขอแค่อ่านได้ (ภาษาลาว) กว่าจะทำให้มันอ่านได้นั้นก็ทำนานมากจำไม่ได้แล้วว่าทำอะไรลงไปบ้าง ยังดีที่ภาษาไทย กับ ลาว ใช้ระบบใกล้เคียงกันเลยพอหาทางออกได้อยู่ นี่ก็ไม่ได้จับโค็ดนาน 2 ปีแล้ว เพราะทำงานเป็นอาร์ทไดกราฟฟิกอย่างเดียวไม่มีเวลาเลย ปีหน้าบอกกับตัวเองไว้แล้วว่าจะกลับเข้าสู่วงการเดิมครับ XD