Monday, March 28, 2016

4. Xếp hình cùng cocos creator (tetris)

Với mục tiêu nhắm đến việc phát triển game là chủ yếu, nên những phần ngoài rìa như UI, ads, social plugin, screen manager tôi sẽ thực hiện trong những bài viết ở giữa cuộc hành trình khám phá thế giới game. Trong những bài viết mở đầu, tôi sẽ không đề cập tới những vấn đề này quá nhiều.

Phân tích game

phần 2, tôi đã thực hiện một game đơn giản trên màn hình nằm ngang (landscape). Trong bài viết này, tôi tiếp tục làm một tựa game đơn giản là Tetris. Và màn hình được chọn lựa để phát triển là màn hình đứng (portrait).

Trước khi cắm cúi vào thực hiện project, tôi cần phải phân tích những yêu cầu của game và đưa ra giải pháp phù hợp. Đây là những bước cơ bản khi làm một tựa game, nên tôi sẽ không đi quá nhanh mà để lỡ mất những chi tiết quan trọng.

Không nhất thiết tôi phải làm giống như các game khác. Đây sẽ là những gì tôi sẽ làm trong game Tetris của mình:
  • Game có các hình khối, mỗi hình khối sẽ có 4 ô vuông mô tả các kí tự I, J, L, O, Z. 
  • Các kí tự này sẽ rơi ngẫu nhiên, mỗi đơn vị thời gian sẽ di chuyển vị trí xuống một đơn vị toạ độ (đúng bằng độ rộng của một ô vuông). 
  • Mỗi khi có thao tác quay, kí tự sẽ quay 1 góc 90 độ. 
  • Mỗi hàng ngang sẽ tương ứng với 16 đơn vị, nếu hàng ngang được phủ kín sẽ biến mất, và các hình khối phía trên hàng ngang sẽ rơi xuống để che lấp hàng ngang đó. 
  • Sẽ có nhiều mức độ khi chơi, có thể có hữu hạn cấp để người chơi giành chiến thắng sau 20 level. Mỗi khi tăng level thì tăng tốc độ rơi của kí tự
  • Thể loại chơi đơn (1 người chơi)
Dựa vào phần mô tả trên, tôi sẽ cần một số assets sau:
  • Image: Hình nền game
  • Image: Hình của 1 ô vuông 
  • Particle: Hiệu ứng khi 1 hàng biến mất 
  • Prefab cho chữ I, J, L, O, Z 

Concepts game

Đây là bản vẽ game concepts của tôi. Thường người ta sẽ sử dụng giấy và viết chì hoặc bảng vẽ để vẽ bằng tay. Tuy nhiên, đối với tôi việc sử dụng phần mềm vẽ sẽ dễ nhìn hơn là dùng giấy viết o_0!

Dựa trên concepts này, tôi chia phần phân tích thành 2 phần bố cụclogic:
- Về layout (bố cục), score và level sẽ là 2 label nằm ở 2 góc như hình trên và align với canvas. Tôi sẽ cần một toạ độ y0 để mô tả vị trí bắt đầu spawn một kí tự bất kì và tại một toạ độ x bất kì nằm trong khoảng nhìn thấy của màn hình. Ở nền, tôi cũng cần một toạ độ y1 để mô tả vị trí thấp nhất của nền.
- Về logic, có một số vấn đề được đặt ra là: 
  1. Khi nào thì kí tự ngừng rơi và kí tự mới rơi tiếp?
  2. Khi nào thì tôi biết được 1 hàng đã bị phủ kín? Nếu nhiều hàng bị phủ kín cùng lúc thì sao?
  3. Khi nào thì start game? Có dấu hiệu nhận biết không?
  4. Khi nào thì lên level? Speed tăng bao nhiêu theo level?
  5. Khi nào thì gameover? Khi gameover thì có hiện gì không? Sau đó thì sao?
  6. Khi nào thì tăng score? và tăng bao nhiêu? 

Tôi sẽ phải trả lời lần lượt từng câu hỏi trước khi bắt tay thực hiện game

Khi nào thì kí tự ngừng rơi và kí tự mới rơi tiếp?
Với kiểu cấu trúc thế này, tôi quyết định sử dụng mảng (array) để mô tả dữ liệu game. Với màn hình đứng, tôi chọn resolution 400x600, mỗi ô vuông 25x25. Như vậy mảng tối đa tôi có thể sử dụng có kích thước 16x24. Tôi chọn mảng 16x20 để chừa 1 khoảng phía trên cho dễ nhìn. Với mỗi ô của kí tự sẽ tương ứng với giá trị là 1, những kí tự đã trở thành nền phía dưới có giá trị là 2, còn khoảng không có giá trị là 0.
Khi tôi duyệt qua những ô của kí tự, nếu như ô phía dưới của bất kì ô nào có giá trị là 2, thì sau 0.5s kí tự sẽ ngừng di chuyển. Giá trị của các ô trong kí tự sẽ chuyển thành 2 và kí tự mới xuất hiện.
Vị trí kí tự mới xuất hiện là từ phía trên của hàng đầu tiên, sau đó thì rơi xuống theo từng ô.

Ví dụ 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0
 0 2 0 0 0 0 0 0 0 2 2 0 0 0 2 0
 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0


Khi nào thì tôi biết được 1 hàng đã bị phủ kín? Nếu nhiều hàng bị phủ kín cùng lúc thì sao?
Với mỗi khi kí tự ngừng rơi, tôi bắt đầu duyệt qua từng hàng từ dưới lên, nếu hàng nào full thì liệt vô danh sạch loại trừ. Khi duyệt qua tất cả các hàng, thì tôi mới bắt đầu xoá từng hàng trong danh sách loại trừ. Với mỗi hàng, tôi hạ các hàng phía trên xuống 1 đơn vị, và cho xuất hiện particle tại hàng đó. 
Sau khi hạ hết các hàng xuống, tôi lại bắt đầu quét lại cho tới khi nào không có hàng nào bị loại trừ thì mới cho xuất hiện kí tự mới

Khi nào thì start game? Có dấu hiệu nhận biết không?
Tôi không chú trọng vào việc biển diễn các màn hình, do đó việc start game sẽ không có dấu hiệu gì nhiều, chỉ cho kí tự rơi xuống để chơi thôi.

Khi nào thì lên level? Speed tăng bao nhiêu theo level?
Khi điểm vượt quá các mốc điểm của level thì sẽ được tăng level. Tôi sẽ có 1 dictionary quy định mốc điểm và mốc speed cho từng level. Hiện tại tôi chưa biết con số cụ thể vì chưa chạy thử game.

Khi nào thì gameover? Khi gameover thì có hiện gì không? Sau đó thì sao?
Khi có một ô trên hàng đầu tiên có giá trị là 2 thì gameover. Khi gameover, tất cả các ô sẽ chuyển thành màu xám, có thể chạy animation từ dưới lên trên. Sau đó replay lại game.

Khi nào thì tăng score? và tăng bao nhiêu? 
Tăng mỗi khi có hàng bị biến mất. Hiện tại tôi cho như sau
1 hàng: 5
2 hàng: 15
3 hàng: 25
4 hàng trở lên: 50

Resources game


Hiện tại tôi đang khá bận công việc, nên đa phần sẽ không viết cụ thể cách làm thế nào. Tôi chỉ chụp hình minh hoạ thôi, mong các bạn thông cảm.



Sunday, March 27, 2016

3. Phụ chương - Tạo lập website để host game

Tạo application trên Openshift

Tôi gọi đây là phụ chương, vì phần này không liên quan nhiều đến việc phát triển game.

Nếu bạn từng đọc qua phần 1 của "Sài Gòn - Hành trình phát triển game", bạn sẽ biết được tôi đã từng làm việc cho một công ty chuyên về outsourcing. Bên đó chuyên làm về website bán lẻ là chính. Cũng nhờ đó mà tôi cũng có chút kinh nghiệm trong việc triển khai một site cá nhân. Tuy nhiên, khác với những công ty hay tập đoàn lớn, các site cá nhân thường có lưu lượng người xem khá ít. Nên lựa chọn việc mua một host hay dedicated server là một điều quá xa xỉ. Có rất nhiều dịch vụ hosting website miễn phí, nhất là các dịch vụ điện toán đám mây (cloud computing). Điển hình tôi đã thử qua Google App Engine, Heroku, Openshift. Nếu phân tích ưu nhược điểm của những dịch vụ này thì bạn có thể tìm hiểu thêm, tôi lười lắm! Sau khoảng thời gian sử dụng thì tôi đang trung thành với Openshift, đảm bảo miễn phí và hoạt động 24/24 cho một trang web cá nhân với lưu lượng thấp.

Trước tiên bạn hãy tạo một tài khoản trên Openshift như tôi. Sau đó vào đường dẫn:

https://openshift.redhat.com/app/console/applications

Click chọn "Add Application" để tạo 1 app mới, có rất nhiều loại ngôn ngữ/framework openshift hỗ trợ. Bạn có thể chọn loại mà bạn quen dùng hoặc yêu thích. Trong chương này, tôi quen với python/django nên sẽ hướng dẫn mọi người theo hướng này. Nếu như bạn muốn tôi viết một hướng dẫn cho ngôn ngữ hay framework khác thì hãy để lại comment bên dưới bài viết.

Tiếp tục với việc tạo lập app trên openshift, sau khi click chọn Django, tôi điền thông tin URL cho website của mình như sau
  

Sau đó chỉ cần click "Create Application" và đợi khoảng vài phút là tôi đã tạo xong app của mình trên Openshift. 

Lấy source code từ openshift về máy

Khi đó, tôi nhận được một trang hướng dẫn các bước tiếp theo ở máy tính của tôi. 

Sau đó bạn mở terminal(Mac hoặc Linux)/cmd(Windows), gõ thử chữ "git" rồi bấm enter xem git đã được cài đặt chưa, nếu chưa thì lên đây tải về rồi cài nhé https://git-scm.com/. Tiếp đến đơn giản chỉ cần làm theo hướng dẫn bằng cách chạy các command line thôi.

Quá trình này sẽ tải về máy bạn thư mục mã nguồn của website của bạn trên openshift. Nếu như bạn chưa có nhiều kiến thức về git, thì hãy bổ sung vào danh sách những công cụ bạn bắt buộc phải biết nhé!
Vì đây là website chạy bằng ngôn ngữ python nên bạn phải download và cài đặt python trên máy của mình(tôi sử dụng Mac có sẵn rồi nên đỡ phải cài) https://www.python.org/

Trong command line, tôi tiếp tục vào bên trong thư mục chứa tập tin setup.py, tôi chạy lệnh cài đặt các thư viện cần thiết để chạy website bằng máy của mình trước (chạy thử nghiệm)

sudo python setup.py install

hoặc cho Windows

python setup.py install

Sau khi cài đặt xong xuôi, tôi vào thư mục chứa tập tin manage.py rồi chạy lệnh sau để migrate database. Nếu bạn đã từng làm qua web thì các model thường được biểu diễn dưới dạng Model trên source code của mình, sau đó sẽ thông qua framework về database mapping với cơ sở dữ liệu bên dưới. Do đó tôi cần phải mapping/sync database và model trước khi start site.

python manage.py migrate

Và start site

python manage.py runserver



Bây giờ mở trình duyệt lên mà kiểm tra thử xem nào http://127.0.0.1:8000/

Ooops! Có lỗi rồi, sửa thôi. Sau khi kiểm tra file settings.py, tôi sửa
DEBUG = os.environ.get('DEBUG') == 'True'
thành
DEBUG = True

Kết quả là, start website local thành công la!

Sau đó trở lại thư mục gốc của project và chạy các lệnh sau để push site lên cloud (openshift)

git add .
git commit -am "init project"
git push


Truy cập thử website của mình http://gamegallery-gamestop.rhcloud.com/, mọi thứ có vẻ ổn.


Tạo lập index page (trang chủ)

Để tạo một page mới, tôi cần phải edit lại file urls.py
from django.conf.urls import include, url
from django.contrib import admin
from django.conf.urls.static import static

import views
import settings

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^admin/', include(admin.site.urls)),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \
              + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Và thêm 1 file views.py trong cùng thư mục với urls.py như sau
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    return render(request, 'index.html')

Edit lại TEMPLATE trong file settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(WSGI_DIR, 'static'),
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
và thêm 1 số dòng sau vào cuối file settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(WSGI_DIR, 'media')
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(WSGI_DIR, 'static')
Sau đó tạo file index.html trong thư mục static
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/media/pickupthestars/web-desktop/index.html">Pick up the stars</a>
</body>
</html>

Tạo lập app page 

phần 2, tôi có làm 1 game gọi là Pick up the stars. Hiện giờ, tôi sẽ build và đẩy game đó lên website của mình.

Tạo thư mục media ngang hàng với thư mục static. Tạo tiếp thư mục pickupthestars trong thư mục media.


Mở Cocos creator lên, vô File --> Build. Và chọn thiết lập như sau để build web app:
Build Path: ...../pickupthestars/web-desktop


Tiếp đến, tôi copy thư mục web-desktop tới thư mục media/pickupthestars của website


Game của tôi đã deploy lên site chạy nội bộ trong máy thành công.


Cuối cùng,  tôi chạy lại các lệnh sau để push những thay đổi site lên cloud (openshift). Mở termial và di chuyển tới thư mục của website rồi chạy các lệnh:

git add .
git commit -am "add game pickup the stars"
git push

Sau khi chạy xong, tôi lên kiểm tra thử http://gamegallery-gamestop.rhcloud.com/ và thấy game của mình đã on fly!

Nếu bạn có kiến thức về HTML, CSS thì hãy trang hoàng cho website của bạn thêm lung linh lộng lẫy hơn nhé. Tôi thường hay tham khảo các template trên đây: http://startbootstrap.com/template-categories/all/

Nếu như bạn cảm thấy không muốn người khác để ý tới trang chủ của mình, bạn nên đơn thuần share link của app mình thôi nhé.
Ví dụ: http://gamegallery-gamestop.rhcloud.com/media/pickupthestars/web-desktop/index.html


Tôi đã làm xong một website đơn giản và đẩy game đầu tay của mình lên internet. Còn bạn thì sao?

Saturday, March 26, 2016

2. Ngày đầu tiên - Mò mẫm Cocos Creator

Sau đâu sẽ có nhiều từ ngữ mang tính chất chuyên ngành, nếu các bạn đọc không hiểu thì hãy xem chúng như những công cụ mà game developer sử dụng để tạo ra một sản phẩm. Giống như người thợ làm bánh, họ có lò nướng, chày giã bột, khay đựng, v.v.... Đối với game developer, thì nó là những framework, studio, hoặc cả một bộ development toolkit. Đừng hoang mang, hãy cùng tôi tham gia cuộc thám hiểm thế giới của game developer nào!

Tôi có một chút kiến thức về game cũng như về game framework cocos2d-x và cocos2d-js. Nhận thấy khả năng sử dụng javascript để tạo game của mình nhanh hơn hẳn c++ (2 ngày so với 2 tuần của cùng 1 project).  Trước đây tôi cũng sử dụng Cocos Studio để layout game nhưng nó dường như thiêu hẳn các công cụ như là: kiểm thử trên nhiều device, scripting, fit screen. Tuy nhiên, với Cocos Creator, sau khoảng 30p tìm hiểu, tôi vẫn chưa thấy chỗ tích hợp sdkbox như Cocos studio, chắc có lẽ phiên bản sau mới có. Thôi, luyên thuyên chuyện tính năng đủ rồi, công cụ này hiện tại rất phù hợp với mục đích của tôi, tạo game trên nền web nhanh gọn lẹ. Chủ yếu là luyện tập khả năng sử dụng resources hiệu quả và tăng cường khả năng scripting. Để push lên một trang web, tôi có mua 1 tên miền và tạo trang web trên đó rồi, khi nào hoàn thành xong sản phẩm đầu tiên, tôi sẽ viết một bài hướng dẫn tạo một trang web trên cloud nhé.

Hừm, tôi vẫn đang lướt qua từng trang hướng dẫn của Cocos Creator, nếu bạn đang là game developer và đang đọc bài blog này thì cùng đọc với tôi cho vui nhé. Đọc xong tôi sẽ update vô bài blog này các khả năng và những gì giúp ích cho mục đích của tôi.

Cocos creator document: http://cocos2d-x.org/docs/editors_and_tools/creator/index.html (nếu bạn không vô được link này thì có lẽ bên chủ site đã đổi đường dẫn, bạn có thể search google keyword: cocos creator documentation)

Đọc...lướt...lướt...lướt....

Đọc xong ví dụ Hello World, tôi có cảm tưởng đây như là một phiên bản Unity từ Cocos2d-x, nhưng cái họ đang có là engine chạy cực ổn đa nền. Nên việc phát triển thêm bộ Creator quả là tuyệt vời, tôi đang mong chờ từng ngày đây. Và bây giờ bắt đầu tiến đến phần hấp dẫn, tạo game đầu tiên trên Cocos Creator, tôi thật rảnh khi vừa đọc document vừa viết blog! Theo như hướng dẫn, thì họ chỉ tôi làm game "Pick Up The Stars". OK, let's go!

Đây là một thể loại game jumping (nhảy), bạn sẽ điều khiển một con quái vật ngố rừng để ăn các vì sao. Document có đưa ra một đường dẫn nhưng tôi không thể load nổi page đó, thôi vậy, đọc tiếp. Bước tiếp theo cần có của game developer là resources. Nên nhớ, bạn là developer chứ không phải artist, đừng đặt nặng vấn đề đồ hoạ khi đang phát triển game, nếu không bạn sẽ ngốn rất nhiều thời gian để làm một việc mà đa phần game developer không thể, đó chính là tạo resources đẹp. Theo kinh nghiệm non nớt của tôi, bạn nên thay các resources trong game bằng những hình khối đơn giản như hình vuông, hình tròn. Hãy chú tâm vào game play!

Tiếp tục việc mò mẫm Cocos creator, tôi phải download resources để có thể tiếp tục làm game hái sao này.
https://github.com/cocos-creator/tutorial-first-game/releases/download/0.7.0/start_project.zip
Sau khi download xong tôi giải nén và bỏ vô thư mục của project tạo bằng Cocos creator. Mọi thứ sẽ trông như thế này:

Hãy thử tưởng tượng bạn sẽ phải tạo 1 số thứ resources thế này xem, tốn thời gian lắm. Tập trung vào việc của mình thôi. Khi đã có resources như bên trên, tiếp theo tôi tạo scene đầu tiên của game này. Tôi đặt tên cho nó là "game". Đây là khoảnh khắc mà bất cứ developer nào cũng từng trải qua, không biết phải đặt tên thế nào cho đẹp, sử dụng cho lâu dài và đọc cho dễ hiểu. Tôi cứ bất chấp hết đặt bừa là "game". 

Tiếp tục là thiết lập Canvas, chỉnh cho nó Fit Height màn hình, mặc xác Width. Thật ra cũng có một bài viết cho vấn đề này tôi đã từng đọc qua. Nhưng thôi, ban đầu thì biết là Fit Height hiện tại nó tiện hơn là Fit Width hay Fit cả hai. 


Trong phần Assets/textures, kéo thả background vào Canvas trong Hierachy. Sau đó chỉnh lại size cho background thành (1360, 960). Điều này đảm bảo cho background có thể phủ được tất cả device.


Tiếp đến tôi kéo thả ground vào Canvas, canh chỉnh vị trí cũng như kích cỡ để được như bên dưới


Tiếp theo, thả quái vật màu tím (PurpleMonster) vào Canvas (đảm bảo nằm dưới ground). Sau đó chỉnh Anchor Point x=0.5, y=0. Thế là việc kéo thả cơ bản đã xong, lúc này tôi cảm thấy chưa bao giờ làm game nó dễ dàng đến thế này. Nhớ đến những ngày tháng ngồi code chay để chạy được một game đơn giản như Pong cũng phải mất đến cả mấy ngày trời, có khi là cả mấy tuần!

Bây giờ tôi sẽ tới phần mà tôi khá yêu thích chính là scripting <3 Không hiểu sao khi nghe tới scripting là lại hưng phấn hẳn lên! Tạo thư mục scripts trong thư mục assets, sau đó tạo 1 file JavaScript tên là Player

Sau đó Add Component cho Player Node

Tiếp theo tôi sửa file script cho Player, viết 1 hàm tạo jump action. Jump Action tượng trưng cho hành vi nhảy múa của con quái vật tím tái! Khi nhảy sẽ có 2 bước, nhảy lên và nhảy xuống, đây là lẽ đương nhiên. Vì nếu chỉ nhảy lên mà không nhảy xuống thì "ếu" phải nhảy mà nó là bay "cmnr"!

Sử dụng hàm onLoad để thiết lập thông tin cho quái vật tím tái khi người chơi load màn hình (scene) của họ. Hiện tại là màn hình game. Nói thêm là trong game sẽ có nhiều màn hình như màn hình chính, màn hình chơi, màn hình tinh chỉnh, màn hình shop mua item, màn hình giới thiệu, hướng dẫn,... Mỗi khi chuyển sang màn hình mới thì hàm onLoad sẽ được gọi, do đó tôi sử dụng nó để thiết lập thông tin ban đầu cho đối tượng nhắm tới, hiện tại là Player.
 Thiết lập input từ bán phím, nút a để lách qua trái, nút d để lách qua phải.
Rồi, nhét vào hàm onLoad thôi, đơn giản ghê ^^
Nếu bạn từng, đang và sẽ làm game developer thì bạn không thể nào không biết một hàm huyền thoại, đó là hàm update(). Hàm này sẽ được call trên từng frame, hầu hết tất cả game framework, engine đều hỗ trợ hàm update này. Một giây thông thường được chia 60 frames, mỗi frame thời gian thực thi tối đa 0.016s (16ms). Ngoài ra, tôi cần ôn lại kiến thức vật lí một tí.
Vận tốc = gia tốc * thời gian.
Quãng đường = vận tốc * thời gian.

Sau đây là mapping cho thông tin vật lí của các biến
xSpeed : vận tốc
accel : gia tốc
maxMoveSpeed: vận tốc tối đa cho phép
dt: thời gian

Ta sẽ có:
xSpeed = accel * dt
Quãng đường di chuyển = xSpeed * dt

Hàm update sẽ như sau

Khoan hãy vội làm tiếp, mấy bữa nay tôi gặp rất nhiều người, cũ có mới có. Cuộc sống đa sắc màu là vậy. Hồi chiều có gặp lại một chị đồng nghiệp cũ. Lúc trước chị ấy làm lead QA, hiện tại đang làm PM cho project của công ty cũ của mình. 2 chị em lâu ngày không gặp nói huyên thuyên đủ chuyện trên trời dưới đất. Một phần liên quan tới game, chị í mô tả tầm nhìn cũng như cái nghiệp của nghề làm game. Tôi cũng chú ý tiếp thu và góp nhặt những ý kiến phụ trợ cho mình sau này. Mục đích làm game của tôi cần có tâm hơn, cái tâm ở đây không phải là tâm huyết, mà là tâm cảm, tâm cam. Tôi không nên làm game chỉ vì sở thích hay chỉ vì đam mê vật chất. Trò chơi mà tôi tạo ra cần có tầm nhìn dài hạn, không phải là vòng đời của game, mà là vòng đời của người chơi game. Có thể bạn nghĩ nó rất lạ, nhưng sau khi nói chuyện với chị ấy về thiền cũng như về game. Tôi đã nghiệm ra khá nhiều điều hay, và điều này càng mài dũa cái tâm của tôi về nghề làm game hơn nữa. Và bây giờ, tôi cần cải thiện cái tầm của mình, đó chính là rèn luyện các sản phẩm game đầu tay của mình.

Tiếp tục với Cocos creator, con quái vật xấu xí tím lịm đã biết nhảy và di chuyển rồi. Trông cũng không đến nỗi nào! Nhưng với những thiết lập này, con quỷ này nó thay đổi vận tốc chậm quá. Bấm nút a hoặc d một hồi lâu nó mới chạy. Tôi cần phải thay đổi gia tốc của nó ngay!

accel=1000

Có vẻ ổn hơn rồi, cảm giác tương tác người dùng đã có. Không còn sự delay như vừa rồi nữa. Tiếp tục, tôi sẽ làm những vì sao. Theo như trong hướng dẫn, các vì sao xuất hiện và biến mất thường xuyên, nên phải sử dụng đến "Prefab". Nghe giống như một thứ gì đó làm sẵn trước hết, rồi sau đó chỉ cần xài thôi mà không cần phải làm lại nhỉ. Việc này sẽ giúp ích khá nhiều để sử dụng lại content trong game cũng như chia sẻ với game khác! Wao, khá giống Unity.

Tiếp theo, tôi tạo thêm một component JavaScript nữa, đặt tên là Star


Thêm 1 property cho script Star

Kéo texture Star lên Hierarchy, rồi Add Component Star vô.


Kéo ngược node này từ Hierarchy xuống Assets để tạo Prefab và xoá node star khỏi Hierarchy.

Lúc này, tôi tạo một file JavaScript tên là Game để phục vụ logic cho trò chơi. Và thêm 1 số properties như sau

Nếu bạn có để ý thì những gì trong properties đều được show trong Inspector. Có thể nói properties như là cách để script của bạn giao tiếp với các Node trong Canvas vậy. Tiếp tục, tạo một empty node tên là game, rồi kéo thả file Game JavaScript vô trong bảng Inspector hoặc bấm nút Add Component trong bảng Inspector (tương tự như Star vậy đó).

Bây giờ, tôi kéo thả Prefab Star trong assets vô trong property Star Prefab ở Inspector. Còn ground và Player thì kéo từ Hierarchy. Tôi có kết quả như sau


Thêm 1 đoạn script để sinh vị trí Star random trong Game JavaScript. Phải đảm bảo là vì sao này nên nằm trong tầm "đụng chạm" của quái vật tím.

groundY: vị trí sát phía trên của nền đất
newStar: một instance được tạo ra từ Prefab Star
randY: random vị trí từ sát phái trên nền đất cho tới vị trí nhảy của người chơi
randX: nằm trong vị trí độ rộng của node game (nên chỉnh lại width cho node game thành 960)

Hiện tại, game chạy đơn giản như sau, ngôi sao sẽ random vị trí "ăn được" của quái vật tím đáng thương.

Bây giờ, tôi sẽ thêm logic để cho quái vật tím của mình có thể ngoạm được những ngôi sao lung linh kia. Phần này sẽ phát huy hết tinh của của scripting cũng như điểm yếu của scripting so với ngôn ngữ lập trình truyền thống.

Trong Game JavaScript file:

Trong Star JavaScript file:

Tôi để ý thấy, khi game bắt đầu chạy, thì ngôi sao vẫn chưa sinh ra. Mỗi khi sinh ra một ngôi sao, tôi lại gán thêm một biến game cho Star Component (tức Star JavaScript file). Trong khi đó, biến game này chưa từng được khởi tạo trong Star JavaScript file. Đây là một đặc tính khá quan trọng của JavaScript để scripting game. Tuy nhiên, điều này sẽ gây khó khăn khi muốn truy ngược lại nếu như các biến kiểu này được tạo quá nhiều và các mối liên hệ quá vong vo. Nên, tôi không lạm dụng đặc điểm này. Thường thì tôi cần phải quy ước một số luật trong dự án của mình, hiện tại là biến game sẽ được gán vô Star JavaScript file mỗi khi có ngôi sao mới được tạo.

Sau đó, Star JavaScript file sẽ sử dụng biến game để truy xuất thông tin về người chơi, tính khoảng cách. Nếu nằm trong tầm "ngoạm" được, thì ngôi sao sẽ biến mất và một ngôi sao khác sẽ được sinh ra, tại một địa điểm bất kì. Đó là logic mà 2 đoạn script phía trên thể hiện.

Tôi tiếp tục làm thêm phần score để thể hiện điểm số. Trước tiên là add 1 label vô scene, và chỉnh các thông số như bên dưới

Kéo thả file font (bf mikado...) vô trong phần File của Label, chỉnh lại size, line height các thứ
Kết quả là

Tạo 1 label slot scoreDisplay trong Game Javascript và tạo 1 biến score với giá trị ban đầu là 0

Thêm hàm update score trong Game JavaScript

Trong Star JavaScript. sử dụng hàm update score mỗi khi quái vật tím xực được ngôi sao

Kéo thả score node trong Canvas vô property scoreDisplay của Game Component

Dừng lại một chút và nhìn lại những gì tôi đã làm được. Layout background, ground, Player, star. Tạo script cho Player di chuyển và nhảy nhót, Star có khả năng bị ăn(hơi hài, đáng lẽ Player ăn star chứ nhỉ !o_0). Star sau khi bị ăn sẽ tự động hồi sinh tại vị trí bất kì mà Player có thể chạm tới. Sau khi Player ăn được Star, score sẽ thay đổi.

Tiếp theo tôi nên làm gì đây nhỉ. Thông thường một game đơn giản sẽ thêm yếu tố nào nữa nhỉ, mải mê scripting một hồi tôi lại quên mất cái cơ bản của một game cần là gì rồi! Đây là một điều mà game developer nên cực kì lưu ý. Chúng ta cần có một cái nhìn tổng quan, một đặc tả về game mà mình muốn tạo ra. Vì tôi đang học làm game, nên các ý tưởng sẽ hình thành từ từ trong lúc làm. Nhưng khi tôi làm game thật sự, tôi mong muốn mình sẽ biết tất cả các yếu tố cần có trong game trước khi bắt tay vào làm. Trong giới phần mềm, yếu tố này thường được gọi là đặc tả yêu cầu. Điều này vô cùng, cực kì quan trọng. Nó như xương sống của cả quá trình làm game. Nếu bị lệch từ khúc xương sống thì khó mà ngồi thẳng và đi đứng ngay ngắn được. Tôi mong muốn game của mình sẽ là một "soái ca" chứ không phải là "chàng gù" lay lất nơi "phố chợ".

Cuối cùng chính là vòng đời của game. Khi nhìn lại kĩ những gì mình đã làm được, tôi thấy có gì đó sai sai. Tự nhiên đùng 1 cái vô là có con gì nó nhảy nhảy, mà nó nhảy hoài không biết khi nào xong. Đó chính là vấn đề. Nếu là game, thì nó sẽ có khởi đầu và kết thúc, giống như một bộ phim vậy. Tôi không dự định hướng tới các thể loại game online hay game không hồi kết lúc này, những gì tôi muốn hướng tới là game có cốt truyện và có điểm kết. Tôi rất thích những câu truyện, những bộ phim. Nhất là những bộ phim khoa học viễn tưởng, phiêu lưu mạo hiểm. Điều này đóng góp khá nhiều cho việc lựa chọn con đường phát triển game của tôi. Tôi gọi nó là "niệm" của tôi khi làm game.

Trong Game JavaScript, thêm 1 số đoạn scripting để gia hạn thời gian người chơi cần phải ăn sao. Nếu trong thời gian quy định mà không ăn thêm được sao thì sẽ thua cuộc (gameover).

Và câu hỏi được đặt ra lúc này là, thời gian giới hạn để ăn sao được hiển thị thế nào để người chơi biết hoặc chí ít cảm nhận được "à, thì ra tại mình không ăn sớm nên mới thua". Về mặt trải nghiệm người dùng, có nhiều cách để thể hiện việc này. Dùng đồng hồ đếm, hiện màn hình hướng dẫn,... Nhưng trong ví dụ này, tôi làm cho ngôi sao mờ dần. Và đến khi biến mất, thì cũng là lúc trò chơi kết thúc (gameover).  Trong Star JavaScript file

Trong Player JavaScript, thềm 1 phần xử lí âm thanh nữa. Mỗi khi con tím lịm nhảy chạm đất thì kêu lên 1 tiếng "búm"! Nhớ kéo thả file âm thanh jump vô Inspector của Player nhé mọi người.


Roài, thêm tiếng khi nhai sao xong ghi điểm nữa. Tương tự như trên, nhưng làm cho Game Javascript khi gainScore

Property mới

Play sound

Và không quên kéo thả score sound vô Game trong Inspector.

Waaaa, xong roài, làm game thật đơn giản. Suy nghĩ trong tôi lúc này là vậy! Tôi sẽ tiếp tục cuộc hành trình tìm kiếm chân lí trong việc phát triển game, cũng như phát triển bản thân tôi. Còn các bạn thì sao?



Next topic: http://saigongamestory.blogspot.com/2016/03/3-phu-chuong-tao-lap-website-e-host-game.html