Location>code7788 >text

Hongmeng Development Case: Tangram

Popularity:20 ℃/2024-11-07 21:43:40

 

[1] Introduction (full code at the end)

The Drag and Drop Tangram Game presented in this article is a simple puzzle game that allows users to complete puzzle tasks by dragging and rotating tangram pieces of different shapes. The whole game is developed using the Hongmeng Next framework, which utilizes its powerful UI building capabilities and data response mechanism to achieve a smooth user experience.

[2] Environmental Preparation

Computer system: windows 10

Development Tools: DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

Engineering version: API 12

Real camera: Mate 60 Pro

Languages: ArkTS, ArkUI

[3] Key Technical Points

1. TangramBlock Class Definition The core of the game lies in the definition of the TangramBlock class, which encapsulates the properties and behaviors of each tangram block. The class contains properties such as width, height, color, initial and current offset, rotation angle, etc. It also provides methods to reset the data. This lays the foundation for subsequent data binding and UI rendering.

2. Data Binding and Responsive Updates Data observation and responsive updates can be easily implemented in Hongmeng Next using the @ObservedV2 and @Trace decorators. Whenever a property in a TangramBlock instance changes, the UI is automatically updated to reflect the latest state. This mechanism greatly simplifies data synchronization, allowing developers to focus on logic implementation without worrying about UI updates.

3. UI Building and Layout Management Hongmeng Next provides a rich set of UI components and layout tools, which makes building complex user interfaces easy. In this project, we use Column, Stack, Polygon and other components to build the layout of Tangram boards. By nesting these components, we can flexibly control the position and size of each board.

4. Gesture Handling and Interaction In order to realize the dragging and rotating functions, we use the PanGesture and rotate methods to handle the user's touch and gesture operations. When the user drags the panel, the position change of the panel can be reflected in real time by updating the initialOffsetX and initialOffsetY properties. Similarly, the rotation effect of the board can be realized by increasing or decreasing the rotationAngle property.

5. Animation and Transition Hongmeng Next has built-in rich animation and transition effects to make user interaction more natural. In this project, we use the animateTo method to smoothly update the state of the board, which enhances the user experience.

5.1 Rotation animation properties

.rotate({
  angle: ,
})

5.2 Flip animation properties

.rotate({
  x: 0,
  y: 1,
  z: 0,
  angle: ,
  centerX:  / 2, // Center x-coordinate
  centerY:  / 2, // Y-coordinate of center point
})

5.3 Translation Animation Properties

.translate({ x: , y: , z: 0 })

[complete code]

@ObservedV2 // Decorator that listens for data changes
class TangramBlock { // Define the tangram class
  width: number; // Width
  height: number; // Height
  points: Array<[number, number]>; // Array of point coordinates
  color: string; // Color
  @Trace initialOffsetX: number; // Initial X offset
  @Trace initialOffsetY: number; // Initial Y offset
  @Trace currentOffsetX: number; // Current X offset
  @Trace currentOffsetY: number; // Current Y offset
  @Trace rotationAngle: number; // Rotation angle
  @Trace flipAngle: number = 0; // Flip angle, default 0
  @Trace rotateValue: number; // Rotation value
  defaultInitialOffsetX: number; // Default initial X offset
  defaultInitialOffsetY: number; // Default initial Y offset
  defaultRotationAngle: number; // Default Rotation Angle

  constructor(color: string, width: number, height: number, initialOffsetX: number, initialOffsetY: number,
    rotationAngle: number, points: Array<[number, number]>) {
     =  =  = initialOffsetX; // Initialize X offset
     =  =  = initialOffsetY; // Initialize the Y offset
     =  =  = rotationAngle; // Initialize rotation angle
     = color; // Setting the color
     = width; // Set the width
     = height; // Set the height
     = points; // Set the array of point coordinates
  }

  resetData() { // Reset data methods
     = 0; // Reset flip angle
     =  = ; // Reset the initial X offset
     =  = ; // Reset the initial Y offset
     =  = ; // Reset rotation angle
  }
}

const baseUnitLength: number = 80; // Basic unit length

@Entry // Entry components
@Component // Define the component
export struct Index { // Main Component
  @State selectedBlockIndex: number = -1; // Current selected position
  @State blocks: TangramBlock[] = [// Tangram Array
  // Small right-angled isosceles triangle
    new TangramBlock("#fed8e5", baseUnitLength, baseUnitLength, -33.58, -58.02, 135,
      [[0, 0], [baseUnitLength, 0], [0, baseUnitLength]]),
    new TangramBlock("#0a0bef", baseUnitLength, baseUnitLength, 78.76, 54.15, 45,
      [[0, 0], [baseUnitLength, 0], [0, baseUnitLength]]),
    // Right-angled isosceles triangle
    new TangramBlock("#ff0d0c", baseUnitLength * (2), baseUnitLength * (2), -33.16, -1.43, -90,
      [[0, 0], [baseUnitLength * (2), 0], [0, baseUnitLength * (2)]]),
    // Large right-angled isosceles triangle
    new TangramBlock("#ffa60a", baseUnitLength * 2, baseUnitLength * 2, 22.46, -172, -135,
      [[0, 0], [baseUnitLength * 2, 0], [0, baseUnitLength * 2]]),
    new TangramBlock("#3da56a", baseUnitLength * 2, baseUnitLength * 2, 135.65, -59.34, -45,
      [[0, 0], [baseUnitLength * 2, 0], [0, baseUnitLength * 2]]),
    // Square
    new TangramBlock("#ffff0b", baseUnitLength, baseUnitLength, 23.07, -1.84, -45,
      [[0, 0], [baseUnitLength, 0], [baseUnitLength, baseUnitLength], [0, baseUnitLength]]),
    // Parallelograms
    new TangramBlock("#5e0b9b", baseUnitLength * 2, baseUnitLength, -61.53, -85.97, 45,
      [[0, 0], [baseUnitLength, 0], [baseUnitLength * 2, baseUnitLength], [baseUnitLength, baseUnitLength]])
  ];

  build() { // Build methodology
    Column({ space: 30 }) { // Create a vertical layout
      Stack() { // Create a stacked layout
        ForEach(, (block: TangramBlock, index: number) => { // Traverse the jigsaw puzzle array
          Stack() { // Create a stacked layout
            Polygon({ width: , height:  })// Drawing polygons
              .points()// Set the polygon vertex coordinates
              .fill()// Fill color
              .draggable(false)// Press and hold for non-drag
              .rotate({ angle:  }) // Rotation angle
          }
          .rotate({
            // Rotate
            x: 0,
            y: 1,
            z: 0,
            angle: ,
            centerX:  / 2, // Center x-coordinate
            centerY:  / 2, // Y-coordinate of center point
          })
          .width() // Set the width
          .height() // Set the height
          .onTouch(() => { // Touch events
             = index; // Set the selected index
          })
          .draggable(false) // Press and hold for non-drag
          .translate({ x: , y: , z: 0 }) // Panning
          .gesture( // Gestures
            PanGesture()// Drag gestures
              .onActionUpdate((event: GestureEvent | undefined) => { // Update events
                if (event) {
                   =  + ; // Update the X offset
                   =  + ; // Update the Y offset
                }
              })
              .onActionEnd((event: GestureEvent | undefined) => { // End event
                if (event) {
                   = ; // Update the current X offset
                   = ; // Update the current Y offset
                }
              })
          )
          .zIndex( == index ? 1 : 0) // Setting the hierarchy
          .borderWidth(2) // Border width
          .borderStyle() // Border Styles
          .borderColor( == index ? "#80a8a8a8" : ) // border color
        })
      }.width('100%').height('750lpx') // Set the width and height
      .backgroundColor("#e4f2f5") // background color


      // Rotation angle counter
      Column({ space: 5 }) { // Create a vertical layout and set the spacing
        Text(`angle of rotation(intervals5)`).fontColor() // Display the rotation angle text and set the font color
        Counter() { // Create the counter component
          Text(`${ != -1 ? [].rotationAngle :
            '-'}`)// Displays the rotation angle or placeholder for the currently selected tangram.
            .fontColor() // Set the font color
        }
        .width(300) // Set the counter width
        .onInc(() => { // Add a button click event
          if ( != -1) {
            animateTo({}, () => {
              [].rotationAngle += 5; // Increase the angle of rotation
            })
          }
        }).onDec(() => { // Reduce button click events
          if ( != -1) {
            animateTo({}, () => {
              [].rotationAngle -= 5; // Reduced rotation angle
            })
          }
        });
      }

      // Rotation angle counter
      Column({ space: 5 }) { // Create a vertical layout and set the spacing
        Text(`angle of rotation(intervals45)`).fontColor() // Display the rotation angle text and set the font color
        Counter() { // Create the counter component
          Text(`${ != -1 ? [].rotationAngle :
            '-'}`)// Displays the rotation angle or placeholder for the currently selected tangram.
            .fontColor() // Set the font color
        }
        .width(300) // Set the counter width
        .onInc(() => { // Add a button click event
          if ( != -1) {
            animateTo({}, () => {
              [].rotationAngle += 45; // Increase the angle of rotation
            })
          }
        }).onDec(() => { // Reduce button click events
          if ( != -1) {
            animateTo({}, () => {
              [].rotationAngle -= 45; // Reduced rotation angle
            })
          }
        });
      }

      // Flip button
      Row() { // Create a horizontal layout
        Button('Flip to the left').onClick(() => { // Left flip button click event
          animateTo({}, () => {
            if ( != -1) {
              [].flipAngle -= 180; // Reduced flip angle
            }
          });
        });

        Button('Flip to the right').onClick(() => { // Right flip button click event
          animateTo({}, () => {
            if ( != -1) {
              [].flipAngle += 180; // Increase flip angle
            }
          });
        });
      }.width('100%').justifyContent() // Set the width and content alignment

      // Reset and hide the border buttons
      Row() { // Create a horizontal layout
        Button('Reset').onClick(() => { // Reset the button click event
          animateTo({}, () => {
            for (let i = 0; i < ; i++) {
              [i].resetData(); // Reset jigsaw data
            }
             = -1; // Reset selected indexes
          });
        });

        Button('Hide border').onClick(() => { // Hide the border button click event
           = -1; // Reset selected indexes
        });
      }.width('100%').justifyContent() // Set width and content alignment
    }.width('100%').height('100%')
  }
}