Jake Tran – Jake Tee https://jakesto.com Game Dev Blog Sun, 10 Dec 2023 03:33:58 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.1 https://jakesto.com/wp-content/uploads/2022/07/cropped-pngwing.com_-32x32.png Jake Tran – Jake Tee https://jakesto.com 32 32 194548219 Rich Text Block – Thay đổi cấu trúc chữ như lập trình web https://jakesto.com/rich-text-block-thay-doi-cau-truc-chu-nhu-lap-trinh-web/?utm_source=rss&utm_medium=rss&utm_campaign=rich-text-block-thay-doi-cau-truc-chu-nhu-lap-trinh-web Sun, 10 Dec 2023 03:33:19 +0000 https://jakesto.com/?p=1005 Nếu anh em nào từng code web thì sẽ quá quen với cấu trúc để thay đổi kiểu chữ <p></p> hay là <title></title>

Tuy nhiên mặc định trong Unreal Engine lại không có sẵn vậy. Giả sử ta có một đoạn chữ sau:

“Tôi yêu lập trình game”

Với web, sẽ rất dễ để ta thay đổi giả sử chữ game thành in đậm, với cú pháp đơn giản là:
<title>Tôi yêu lập trình <p>game</p></title>

Còn trong Unreal, ta sẽ phải làm như thế này:

May mắn là do chữ game ở cuối, nên ta chỉ cần 2 TextBlock, nếu không sẽ cần nhiều hơn thế chỉ cho một đoạn chữ đơn giản.

Càng nhiều text block, càng tốn tài nguyên xử lí thêm. Để giải quyết vấn đề này, Unreal đã cung cấp một giải pháp tương tự như code web, đó là Rich Text Block.

Cách sử dụng

Tạo DataTable với cấu trúc dữ liệu là RichTextStyleRow

Mình sẽ đặt tên là TextStyles.

Khi mở lên ta sẽ thấy một bảng trống, ấn Add để thêm dữ liệu mới vào.

Ở cột Row Name, đó sẽ là tên cú pháp của chúng ta. Trong ví dụ này mình thêm p để sử dụng cho in đậm chữ.

Ở phần tùy chỉnh bên dưới sẽ, ta cũng sẽ chọn Font Family thành Roboto, và Typeface là Bold.

Cuối cùng, quay lại ví dụ trên, ta sẽ bỏ đi 2 TextBlock cũ, và thay vào bằng 1 RichTextBlock

Ở phần cài đặt, chọn TextStyles table mà ta đã tạo ở bước trước.
Lúc này chữ sẽ lỗi do không tìm thấy style mặc định, ta có thể tick vào Override Default Style và set style mặc định cho nó:

Cuối cùng, ta sẽ format dòng chữ “Tôi yêu lập trình game” -> Tôi yêu lập trình <p>game</> và kết quả:

Lưu ý: Rich Text Block có vẻ vẫn chưa hỗ trợ cấu trúc tròng theo kiểu <h1>hello<p>world</></> nên anh em lưu ý.

]]>
1005
Tại sao gần đây mình không có bài gì mới https://jakesto.com/tai-sao-gan-day-minh-khong-co-bai-gi-moi/?utm_source=rss&utm_medium=rss&utm_campaign=tai-sao-gan-day-minh-khong-co-bai-gi-moi Sun, 19 Nov 2023 02:53:12 +0000 https://jakesto.com/?p=1000 Xin chào mọi người, mọi người có thể thấy là bài cuối mình viết là từ tháng 3. Trong thời gian qua mình khá bận với việc chưa có ý tưởng để viết bài 😂 Nên nếu mọi người muốn mình viết gì về tính năng hay tips thì cứ comment nhé.

Mình cũng muốn share cho mọi người khóa học tiếng việt Unreal Engine rất chất lượng của một bạn trong nhóm.

https://www.udemy.com/user/brandon-vox/

]]>
1000
101 Tips – Stack Trace https://jakesto.com/101-tips-stack-trace/?utm_source=rss&utm_medium=rss&utm_campaign=101-tips-stack-trace Sun, 19 Mar 2023 14:57:30 +0000 https://jakesto.com/?p=980 Khi debug lỗi, hẳn các bạn sẽ không lạ việc tìm kiếm xem hàm đó hoặc sự kiện đó được gọi ở đâu. Trong c++, cách thường làm đó là thêm break point vào dòng code cần xem. Thế còn trong Blueprint thì làm như thế nào?
Câu trả lời là Stack Trace.

Giả sử ta có 1 hàm tên là PrintHelloWorld, chỉ đơn giản là Print String ra màn hình dòng “Hello World” như sau:

Để biết được hàm PrintHelloWorld này được gọi từ object nào, chỉ việc thêm Stack Trace vào nối hàm:

Sau khi hàm PrintHelloWorld được gọi, ta sẽ biết được nguồn gốc của việc gọi đó:

LogBlueprintUserMessages: Script call stack:
Function /Game/Blueprints/BP_MyCharacter.BP_MyCharacter_C:InpActEvt_T_K2Node_InputKeyEvent_0
Function /Game/Blueprints/BP_MyCharacter.BP_MyCharacter_C:ExecuteUbergraph_BP_MyCharacter
Function /Game/Blueprints/BP_MyCharacter.BP_MyCharacter_C:PrintHelloWorld
Function /Game/Blueprints/BP_MyCharacter.BP_MyCharacter_C:ExecuteUbergraph_BP_MyCharacter
LogBlueprintUserMessages: [BP_MyCharacter_C_0] Hello World!

Như ở ví dụ trên, PrintHelloWorld được gọi trong BP_MyCharacter, ở sự kiện ấn nút T.

]]>
980
Cơ bản networking https://jakesto.com/co-ban-networking-phan-1/?utm_source=rss&utm_medium=rss&utm_campaign=co-ban-networking-phan-1 Sun, 30 Oct 2022 12:59:55 +0000 https://jakesto.com/?p=968 Phần 1

Trong phần này mình sẽ đi qua 2 khái niệm cơ bản đó là mô hình mạngquyền mạng.

Để tóm gọn, thì mô hình mạng phổ biến đó là Client-Server, với Server sẽ là trung tâm chính quản lí và lưu trữ dữ liệu gốc, sau đó gửi thông tin tới các người dùng. Mọi hoạt động thay đổi các giá trị online đều phải được thông qua bởi Server.

Với role, thì các Actor trong thế giới, luôn có 2 role đó là Local RoleRemote Role. Trong đó, từ phía các Actor, Remote Role sẽ luôn là Role_Authority bởi các Actor có trạng thái online luôn được sở hữu bởi Server. Trong khi Local Role sẽ phụ thuộc vào đối tượng.

Nếu Actor được điều khiển bởi chính người chơi, Local Role sẽ là Role_AutonomousProxy, và với các đối tượng khác sẽ là Role_SimulatedProxy.

Phần 2

Trong phần 2, mình đi qua khái niệm của Remote Procedural Call. Bao gồm các loại:

  • Server Execute: rpc gọi từ dưới client lên server để yêu cầu thực thi một sự kiện hay hành động
  • Client Execute: rpc gọi từ server về phía đối tượng client cụ thể để thực thi một sự kiện hay hành động
  • NetMulticast: rpc gọi từ server tới tất cả đối tượng client trong vùng không gian cho phép để thực thi một sự kiện hay hành động

Phần 3

Trong phần cuối, mình đi qua:

  • OnRep: thuộc tính bắt buộc các sự kiện đi kèm của một giá trị khi có thay đổi.
  • So sánh OnRep và Multicast: OnRep sẽ luôn được gọi khi client trong vùng không gian hỗ trợ hoặc khi vừa có kết nối tới Server. Multicast chỉ gọi một lần tại thời điểm cụ thể và sẽ bị quên đi.
  • Reliable và Unreliable: Reliable là thuộc tính của RPC cho phép Engine ưu tiên để gửi đi, và Unreliable là ngược lại.
]]>
968
Deverse World https://jakesto.com/deverse-world/?utm_source=rss&utm_medium=rss&utm_campaign=deverse-world Sat, 15 Oct 2022 13:34:07 +0000 https://jakesto.com/?p=958 Xin giới thiệu tới mọi người dự án mình đã phát triển thời gian qua Deverse World.

Deverse World là:
  • Vũ trụ kĩ thuật số ảo.
  • Nền tảng phát triển trò chơi, cung cấp công cụ và giải pháp để tạo ra game nhanh nhất.
  • Người chơi có thể trở thành bất cứ ai, chơi bất cứ gì và ở bất cứ đâu.

Một số hình ảnh game

Kho đồ avatar của người chơi

Trong thời gian tới, mình sẽ tiến hành phát triển các templates cũng như là objects phục vụ cho người dùng xây dựng trò chơi. Hy vọng sẽ được sự ủng hộ của mọi người!
Link website: https://www.deverse.world

]]>
958
101 Tips – Mở level kèm tham số https://jakesto.com/101-tips-mo-level-kem-tham-so/?utm_source=rss&utm_medium=rss&utm_campaign=101-tips-mo-level-kem-tham-so Sun, 18 Sep 2022 12:55:28 +0000 https://jakesto.com/?p=945 Có nhiều mục đích khi mở level kèm tham số. Ví dụ bạn cần kiểm tra xem level trước đó của người chơi là gì, hoặc chỉ đơn giản là muốn truyền một tham số để khi vừa qua level mới có thể sử dụng ngay.
Có nhiều cách để có thể truyền tham số khi mở một level mới, ví dụ như lưu vào GameInstance, rồi sau khi level đã load xong, ta lấy ra sử dụng. Nhưng thứ thế ta lại phải tạo một hay nhiều biến mới không cần thiết.

Một cách đơn giản đó là ta truyền tham số kèm với khi mở một level mới bằng hàm OpenLevel phổ biến

Nếu bạn không thấy mục Absolute và Options ở dưới, chỉ việc click vào mũi tên để xổ ra.

Vùng Options cho phép ta truyền vào một hay nhiều tham số, được ngăn cách nhau bởi dấu “?”:

?PreviousLevel=MyLevel1?MyScore=20

Ở ví dụ trên, ta sẽ truyền qua Level mới giá trị PreviousLevel (level trước đó) là MyLevel1, MyScore là 20.

Tiếp đến, để sử dụng những tham số vừa truyền, ta vào class GameMode. Nếu bạn chưa biết GameMode là gì, có thể tham khảo lại bài viết này: https://jakesto.com/index.php/2020/03/01/unreal-engine-4-framework-gamemode/

Chuột phải vào Event Graph, và tìm cụm từ Options String, đó chính là đoạn Options mà bạn truyền vào ở trên. Tiếp đó ta chỉ cần Parse đoạn string đó với key tương ứng:

Như vậy đã xong, với cách này, bạn đã có thể thoải mái đem giá trị từ level này sang level khác mà không cần lo việc tạo quá nhiều biến.

]]>
945
Unreal Engine 5 – Motion Warping https://jakesto.com/unreal-engine-5-motion-warping/?utm_source=rss&utm_medium=rss&utm_campaign=unreal-engine-5-motion-warping Sat, 02 Jul 2022 08:58:28 +0000 https://jakesto.com/?p=903 Unreal Engine 5 đã cung cấp rất nhiều plugins cũng như tính năng mới tới người dùng. Một tính năng mình thấy rất thích đó là Motion Warping.

Nói tóm tắt:

  • Motion Warping thay đổi Root Motion giữa các frame được định trước từ Montage.
  • Motion Warping thay đổi được transform của animation tại runtime bằng logic từ blueprint hay c++ mà không phải sửa animation.

Trong project mẫu Ancient Valley của Epic Games, nó được sử dụng trong đoạn nhảy qua tảng đá:

Deverse World Attack Motion Warping

Có rất nhiều ứng dụng của Motion Warping, ví dụ như khi player thực hiện combat, cần animation đấm/đá/tấn công quay vào hướng đối tượng.

Trong ví dụ sau, mình sẽ ứng dụng vào sự kiện tấn công tầm gần, sử dụng ví dụ của Paragon : Crunch.

Trước tiên, ta hãy bật plugin Motion Warping từ Plugins.

Trước tiên ta có thể thêm 1 số mục tiêu cần tấn công vào. Mình sẽ sử dụng class nhân vật cơ bản của Unreal, bạn có thể sử dụng gì cũng được.

Mục tiêu của mình là làm cho Crunch tấn công theo các mục tiêu đặt sẵn cũng như là quay hướng đánh vào đúng đối tượng.

Trước tiên ta phải update animation để sử dụng Motion Warping.

Mở animation đánh lên, và tick vào Enable Root Motion:

LƯU Ý: Motion Warping chỉ dùng được khi animation có Root Motion nhé, tức là xương root có thay đổi về vị trí trong animation data.

Bởi vì animation paragon không có Root Motion, nên mình phải sửa tay animation xương root cho di chuyển lên trước. Bạn có thể dễ dàng làm việc này bằng các phần mềm 3D hoặc là dùng additive trong UE rồi xuất ra lại file animation.

Sau khi xong, ta mở montage tấn công lên, trong trường hợp này là mình dùng file Ability_Combo_03_Montage đã có sẵn.

Thay đổi vùng warp theo ý bạn muốn, thông thường sẽ là khi bắt đầu tấn công và kết thúc khi đã ra đòn.

Như vậy là Crunch sẽ warp vị trí và góc quay trong đoạn thời gian vạch ở vùng MotionWarping.

Bước cuối cùng là setup thuộc tính, click vào MotionWarping, bên vùng Details, setup như sau:

  • Root Motion Modifier: loại warp, phổ biến là Skew Warp
  • Warp Target Name: tên sự kiện Warp, bạn có thể set thành gì cũng được. Tên sẽ được sử dụng để cập nhật thông tin cho montage từ logic game.
  • Warp Translation: có muốn warp vị trí không, mặc định là có.
  • Ignore ZAxis: bỏ qua warp theo trục thẳng (trên/dưới).
  • Warp Rotation: có muốn warp góc quay không, mặc định là có.

Như vậy là đã hoàn thành khâu setup cho montage. Ta chuyển qua setup logic cho BP.

Bộ nhân vật Paragon : Crunch đã cung cấp sẵn cho ta blueprint nhân vật CrunchPlayerCharacter. Mở nó lên và thêm Motion Warping component vào vùng Components.

Từ component MotionWarping, kéo thả vào graph và tìm kiếm hàm Add or Update Warp Target from Location and Rotation:

Ở logic trên, mình chỉ đơn giản là lấy blueprint nhân vật mẫu BP_ThirdPersonCharacter của UE trong level, lấy vị trí của nhân vật nối vô Target Location, sau đó tính toán góc cần quay của đối tượng với Crunch. Mình chỉ dùng Target Rotation Z là tại vì mình không muốn Crunch quay lên trời cũng như nghiêng người.

Bước cuối cùng chỉ là play animation montage đã setup ở trên.

LƯU Ý: lí do mình ngắt 2 node Play Anim Montage ở trên là vì animation của chúng không có root motion. Nếu bạn có thì cứ nối bình thường nhé.

Thành quả:

]]>
903
101 Tips – Lightning channel https://jakesto.com/101-tips-lightning-channel/?utm_source=rss&utm_medium=rss&utm_campaign=101-tips-lightning-channel Sat, 28 May 2022 13:54:06 +0000 https://jakesto.com/?p=895 Có bao giờ bạn muốn đèn chỉ cast ánh sáng lên một số vật thể nhất định trong scene? Hay là chỉ đơn giản là muốn hạn chế ánh sáng cast lên quá nhiều vật thể để tối ưu hiệu năng? Trong Unreal Engine có một tính năng khá hay đó là Lighting Channel.

UE cung cấp cho người dùng 3 channel để sử dụng, và mặc định luôn là Channel 0.

Để thay đổi Lightning Channel, tìm kiếm giá trị Lightning Channel trong vùng Details của ánh sáng, bỏ check Channel 0 và đánh dấu vào Channel 1:

Làm tương tự với các vật thể mà bạn muốn ánh sáng được cast lên. Kết quả ta sẽ có như sau:

Như vậy toàn bộ scene đã không còn được nhận ánh sáng từ DirectionalLight, trừ khối hộp bên trái đã chuyển Lightning Channel sang 1.

]]>
895
Tổng hợp các bài viết ngẫu nhiên https://jakesto.com/tong-hop-bai-viet-random/?utm_source=rss&utm_medium=rss&utm_campaign=tong-hop-bai-viet-random Tue, 03 May 2022 15:18:32 +0000 https://jakesto.com/?p=884 Quy trình

Cách fornite kiểm soát quy trình công việc với UnrealGameSync

Địa ngục render

Cách tối ưu hóa dành cho thiết kế mô đun

Nghệ thuật tối ưu

Sách cầm tay cho người kinh doanh game

Hiệu năng cần thiết cho Valorant

Phát triển, lập trình

Netcode không hiệu quả ra sao

Server 128-tick của Valorant

Sử dụng ChunkDownloader

Stream assets trong C++

Phân tích module network của Unreal Engine (tiếng Trung)

Xây dựng thế giới ở No Man’s Sky sử dụng toán học

Series làm game MMORPG

Khám phá sự bí ẩn của Soft Object Reference

Object Reference là gì

Plugin hỗ trợ giao tiếp với dedicated server thông quan rcon

Mô phỏng trực quan components

Chức năng tạo liên tục thế giới trong No Man’s Sky

Âm thanh

Tại sao tiếng súng trong Call of Duty : Modern Warfare nghe đã vậy

Làm thế nào để tạo tiếng súng hay cho games

Thiết kế, diễn hoạt hình

Plugin convert mixamo sang mannequin cho blender

Shader và gameplay của Valorant

Làm sao để Unreal trông thật và điện ảnh hơn

]]>
884
101 Tips – Format text https://jakesto.com/101-tips-format-text/?utm_source=rss&utm_medium=rss&utm_campaign=101-tips-format-text Tue, 29 Mar 2022 14:00:14 +0000 https://jakesto.com/?p=875 Đây là một tip khá hay để có thể format đoạn chữ. Cách phổ biến mọi người hay dùng thường là sử dụng Append String:

Cách này có một hạn chế lớn đó là khi cấu trúc câu trở nên phức tạp thì việc thêm pin vô sẽ rất rườm rà. Thay vào đó ta có thể sử dụng Format Text:

Với cách này, ta có thể thêm pin vào bằng cách sử dụng cú pháp {char} với char có thể là bất cứ kí tự chữ số nào miễn là không trùng nhau.

Ngoài ra, sử dụng Format Text, các đầu nối pin sẽ không phải convert sang dạng String như khi dùng Append String, ta chỉ việc đổi Text thành String sau cùng.

]]>
875