Location>code7788 >text

Hongmeng NEXT Development Case: Coin Tossing

Popularity:363 ℃/2024-11-11 04:09:23

 

[1] Introduction (full code at the end)

This project aims to implement a simple "Coin Toss" function that allows the user to simulate the process of tossing a coin by clicking on the gopher icon on the screen. The application will record and display the number of times the coin appears on the front side (gopher side) and the back side (number 100 side). To enhance the user experience, we also added animation effects to make the coin tossing process more vivid and interesting.

[2] Environmental Preparation

Computer system: windows 10

Development Tools: DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

Engineering version: API 12

The real one: mate60 pro

Languages: ArkTS, ArkUI

[3] Application Structure

The application consists of two main parts: the gopher component (Hamster) and the main page component (CoinTossPage).

Gopher component (Hamster)

The gopher component is one of the core visual elements of the application and is responsible for displaying the image of the gopher. The component is defined through the @Component decorator and receives a property cellWidth, which is used to control the size of the component.

Main page component (CoinTossPage)

The main page component is the entry point to the entire application and is responsible for organizing and managing the various UI elements. This component is also defined through the @Component decorator and contains several state variables for tracking the state of the coins and the progress of the animation.

[4] Function Analysis

1. Gopher components:

- A gopher image was created by combining multiple graphic elements through a Stack layout.

- Each graphic element is set with a specific size, color, border, and other styles, and its position is adjusted with the margin attribute.

2. Main page components:

- At the top is a "coin flip" header, and below that is a row layout showing the gopher components and the number of times they appear heads and tails.

- The gopher component is placed in a circular area with a linear gradient color background.

- When you click on the gopher, a series of animation effects are triggered, simulating the process of a coin being tossed up and then falling down.

- By calculating the final angle, determine whether it is front or back facing up and update the count accordingly.

[complete code]

// Define the gopher component
@Component
struct Hamster {
  @Prop cellWidth: number // Cell width

  build() {
    Stack() { // Create a stacked layout
      // Body
      Text()
        .width(`${ / 2}lpx`)// The width is half the width of the cell
        .height(`${ / 3 * 2}lpx`)// Height is 2/3 of the cell height
        .backgroundColor("#b49579")// background color
        .borderRadius({ topLeft: '50%', topRight: '50%' })// Rounded corners
        .borderColor("#2a272d")// border color
        .borderWidth(1) // Border width
      // Mouth
      Ellipse()
        .width(`${ / 4}lpx`)// Width of the mouth
        .height(`${ / 5}lpx`)// Height of the mouth
        .fillOpacity(1)// Fill opacity
        .fill("#e7bad7")// Fill color
        .stroke("#563e3f")// border color
        .strokeWidth(1)// Border width
        .margin({ top: `${ / 6}lpx` }) // Top margin
      // Left eye
      Ellipse()
        .width(`${ / 9}lpx`)// Width of the left eye
        .height(`${ / 6}lpx`)// Left eye height
        .fillOpacity(1)// Fill opacity
        .fill("#313028")// Fill color
        .stroke("#2e2018")// border color
        .strokeWidth(1)// Border width
        .margin({ bottom: `${ / 3}lpx`, right: `${ / 6}lpx` }) // Bottom and right margins
      // Right eye
      Ellipse()
        .width(`${ / 9}lpx`)// Width of the right eye
        .height(`${ / 6}lpx`)// Right eye height
        .fillOpacity(1)// Fill opacity
        .fill("#313028")// Fill color
        .stroke("#2e2018")// border color
        .strokeWidth(1)// Border width
        .margin({ bottom: `${ / 3}lpx`, left: `${ / 6}lpx` }) // Bottom and left margins
      // Left eye pupil
      Ellipse()
        .width(`${ / 20}lpx`)// Pupil width of the left eye
        .height(`${ / 15}lpx`)// Height of the left pupil
        .fillOpacity(1)// Fill opacity
        .fill("#fefbfa")// Fill color
        .margin({ bottom: `${ / 2.5}lpx`, right: `${ / 6}lpx` }) // Bottom and right margins
      // Right pupil
      Ellipse()
        .width(`${ / 20}lpx`)// Pupil width of the right eye
        .height(`${ / 15}lpx`)// Pupil height of the right eye
        .fillOpacity(1)// Fill opacity
        .fill("#fefbfa")// Fill color
        .margin({ bottom: `${ / 2.5}lpx`, left: `${ / 6}lpx` }) // Bottom and left margins
    }.width(`${}lpx`).height(`${}lpx`) // Set the width and height of the component
  }
}

// Define page components
@Entry
@Component
struct CoinTossPage {
  @State cellWidth: number = 50 // Cell width
  @State headsCount: number = 0 // Number of times face up
  @State tailsCount: number = 0 // Number of times the reverse side is up
  @State rotationAngle: number = 0 // Rotation angle
  @State verticalOffset: number = 0 // Longitudinal displacement
  @State isAnimRun: boolean = false // Whether the animation is executing or not

  build() {
    Column() {
      // Page title
      Text('Flip a coin')
        .height(50)// Height set to 50
        .width('100%')// Width set to 100%
        .textAlign()// Center-align text
        .fontColor("#fefefe")// font color
        .fontSize(20); // Font size

      // Gopher display and count
      Row({ space: 20 }) {
        Stack() {
          Hamster({ cellWidth:  }) // Create the gopher component
        }
        .borderRadius('50%') // Setting rounded corners
        .width(`${}lpx`) // Set the width
        .height(`${}lpx`) // Set the height
        .linearGradient({
          // Set a linear gradient background
          direction: ,
          colors: [['#ebcf2f', 0.0], ['#fef888', 0.5], ['#ebcf2f', 1.0]]
        });

        // Number of times reverse face-up is displayed
        Text(`${}`)
          .fontSize(20)
          .fontColor("#fefefe");

        Stack() {
          // Display 100
          Text("100")
            .fontColor("#9f7606")
            .fontSize(`${ / 2}lpx`);
        }
        .borderRadius('50%') // Setting rounded corners
        .width(`${}lpx`) // Set the width
        .height(`${}lpx`) // Set the height
        .linearGradient({
          // Set a linear gradient background
          direction: ,
          colors: [['#ebcf2f', 0.0], ['#fef888', 0.5], ['#ebcf2f', 1.0]]
        });

        // Show the number of times the front side is facing up
        Text(`${}`)
          .fontSize(20)
          .fontColor("#fefefe");

      }.width('100%').justifyContent(); // Set the width and center the content

      Stack() {
        Stack() {
          // Create a magnified version of the gopher component
          Hamster({ cellWidth:  * 3 })
            .visibility(() ?  : ); // Show or hide according to status

          // Display 100
          Text("100")
            .fontColor("#9f7606")// font color
            .fontSize(`${ / 2 * 3}lpx`)// Font size
            .visibility(!() ?  : )// Show or hide according to status
            .rotate({
              // Rotate 180 degrees
              x: 1,
              y: 0,
              z: 0,
              angle: 180
            });
        }
        .borderRadius('50%') // Setting rounded corners
        .width(`${ * 3}lpx`) // Set the width
        .height(`${ * 3}lpx`) // Set the height
        .linearGradient({
          // Set a linear gradient background
          direction: ,
          colors: [['#ebcf2f', 0.0], ['#fef888', 0.5], ['#ebcf2f', 1.0]]
        })
        .rotate({
          // Rotate according to the current angle
          x: 1,
          y: 0,
          z: 0,
          angle: 
        })
        .translate({ x: 0, y:  }) // Setting the longitudinal displacement
        .onClick(() => { // Click event handling

          if () {
            return;
          }
           = true

          let maxAnimationSteps = 2 * (10 + (() * 10)); // Calculate the maximum number of animations
          let totalAnimationDuration = 2000; // Total length of animation

          // First animation, throw up
          animateToImmediately({
            duration: totalAnimationDuration / 2, // Animation is half of the total duration
            onFinish: () => { // Callback when the animation is complete
              // Second animation, falling
              animateToImmediately({
                duration: totalAnimationDuration / 2,
                onFinish: () => {
                   =  % 360; // Make sure the angle is between 0 and 360
                  // Determine which face is currently displayed
                  if (()) { // If it's gopher noodles
                    ++; // Add 1 to the number of times the reverse side is up
                  } else { // If it's the other way around
                    ++; // Add 1 to the number of times you face up
                  }
                   = false
                }
              }, () => {
                 = 0; // Reset longitudinal displacement
              });
            }
          }, () => {
            // Set the vertical displacement to simulate the effect of a coin flip
             = -100 * (1 + (() * 5)); // Randomly set upward displacement
          });

          // Looping animation to add a rotational effect
          for (let i = 0; i < maxAnimationSteps; i++) {
            animateToImmediately({
              delay: i * totalAnimationDuration / maxAnimationSteps, // Set the delay for each animation
              duration: 100, // Duration of each animation
              onFinish: () => {
                // Callback when the animation is complete
              }
            }, () => {
               += 90; // Increase rotation by 90 degrees at a time
            });
          }
        });

      }.width('100%').layoutWeight(1).align().padding({ bottom: 80 }); // Set the component's width, weight, alignment, and bottom inner margins
    }
    .height('100%') // Set the height of the entire page
    .width('100%') // Set the width of the entire page
    .backgroundColor("#0b0d0c"); // set the background color
  }

  // Determine if the gopher face is currently displayed
  isHeadsFaceUp() {
    let normalizedAngle =  % 360; // Normative perspective
    // Determine the angle range to show or not show the gopher surface.
    if (normalizedAngle >= 0 && normalizedAngle < 90 || normalizedAngle >= 270 && normalizedAngle <= 360) {
      return true; // show gopher face
    }
    return false; // Show reverse
  }
}