Read the original article:Building 2048 with ArkTS 1
Introduction
Hello, everyone! In this article, we’ll take an exciting journey to create the classic 2048 game using ArkTS and ArkUI. We’ll explore its core mechanics, design principles, and step-by-step implementation using these powerful technologies. Let’s dive in and bring 2048 to life!
Let’s create the UI
Defining Colors
To have the best game, we need colors and we need them now. Thus, we will use the “color.json” file to define them.
{
"name": "color_background",
"value": "#faf8ef"
},
{
"name": "color_board",
"value": "#776e65"
},
{
"name": "color_empty",
"value": "#ccc0b3"
},
{
"name": "color_2",
"value": "#eee4da"
},
{
"name": "color_4",
"value": "#ede0c8"
},
{
"name": "color_8",
"value": "#f2b179"
},
{
"name": "color_16",
"value": "#f59563"
},
{
"name": "color_32",
"value": "#f67c5f"
},
{
"name": "color_64",
"value": "#f65e3b"
},
{
"name": "color_128",
"value": "#edcf72"
},
{
"name": "color_256",
"value": "#edcc61"
},
{
"name": "color_512",
"value": "#edc850"
},
{
"name": "color_1024",
"value": "#edc53f"
},
{
"name": "color_2048",
"value": "#edc22e"
}
Adding Game Board
We will use the Grid component with 4 rows and 4 columns to create the game board.
@Entry
@Component
struct Index {
build() {
RelativeContainer() {
Grid() {
}
// 70% to fit the square board into circular watch
.size({ width: '70%', height: '70%' })
// center the board
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr')
// styles, change as you wish
.columnsGap(4)
.rowsGap(4)
.padding(4)
.backgroundColor($r('app.color.color_board'))
.borderRadius(4)
}
.height('100%')
.width('100%')
}
}
Adding Tile
We will use the power of ArkTS to create a custom component to define our tile.
- But first, we will define game numbers to make our code more readable and place it under the model directory.
export enum GameNum {
_0 = 0, // we will use 0 for empty cells
_2 = 2,
_4 = 4,
_8 = 8,
_16 = 16,
_32 = 32,
_64 = 64,
_128 = 128,
_256 = 256,
_512 = 512,
_1024 = 1024,
_2048 = 2048
}
- Let’s define our tile: Create the components directory and place GameTile under it.
import { GameNum } from '../model/GameNum';
@Component
export default struct GameTile {
@Require num: GameNum;
build() {
RelativeContainer() {
if (this.num != GameNum._0) {
Text(this.num.toString())
.fontColor(this.textColor())
.fontSize(14)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
}
.height('100%')
.width('100%')
.borderRadius(4)
.backgroundColor(this.cellColor())
}
// set text color based on the GameNum
textColor() {
return this.num < GameNum._8 ? Color.Black : Color.White
}
// Set cell color based on the GameNum
cellColor() {
switch (this.num) {
case GameNum._0:
return $r('app.color.color_empty')
case GameNum._2:
return $r('app.color.color_2')
case GameNum._4:
return $r('app.color.color_4')
case GameNum._8:
return $r('app.color.color_8')
case GameNum._16:
return $r('app.color.color_16')
case GameNum._32:
return $r('app.color.color_32')
case GameNum._64:
return $r('app.color.color_64')
case GameNum._128:
return $r('app.color.color_128')
case GameNum._256:
return $r('app.color.color_256')
case GameNum._512:
return $r('app.color.color_512')
case GameNum._1024:
return $r('app.color.color_1024')
case GameNum._2048:
return $r('app.color.color_2048')
}
}
}
Adding Gestures
So far, we have created the user interface. Now we will add gestures to move tiles. We will use the PanGesture to catch swipe actions.
RelativeContainer() {
// ...
}
.height('100%')
.width('100%')
.gesture(PanGesture({ distance: 50 }).onActionEnd((event) => {
const verticalDistance = event.offsetY;
const horizontalDistance = event.offsetX;
if (Math.abs(verticalDistance) > Math.abs(horizontalDistance)) { // vertical movement
if (verticalDistance < 0) { // swipe up
console.log('up');
} else { // swipe down
console.log('down')
}
} else { // horizontal movement
if (horizontalDistance < 0) { // swipe left
console.log('left')
} else { // swipe right
console.log('right')
}
}
}))
Conlusion
Every magic starts with a simple idea and some courage. So far, we have created the user interface for our game. We will continue with the game logic in part 2. See you soon. :)



Top comments (0)