[Beginner] android app that rolls a ball using a sensor [Java]

Udemy's android development course is too fast

https://www.udemy.com/androidjavapro/

Java knowledge zero OK! Master course to become a professional Android developer [Compatible with the latest Android Studio 3! ] Easy-to-understand and polite commentary! Let's master the basics of Java, the knowledge required as an Android engineer, list view, database creation, and attractive design through abundant samples! 3.9 (182 ratings) 1449 students registered Creator Hiroaki Kaneda Last updated 1/2019

I'm taking this course and the pace is too fast There were some parts that I couldn't understand without detailed explanations, so I'll post a comment so that I can understand it.

python


package com.example.accball;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/*The event listener keeps an eye on the event and receives it if it exists*/
public class MainActivity extends AppCompatActivity implements SensorEventListener, SurfaceHolder.Callback {

    //Declaration of member variables(=Add a lowercase m at the beginning)
    SensorManager mSensorManager;
    Sensor mAccSensor;

    //Declaration of a member variable called mHolder of the SurfaceHolder class
    //Think of it as a holder for temporarily storing the screen.
    SurfaceHolder mHolder;
    int mSurfaceWidth;      //width of surfaceView
    int mSurfaceHeight;     //height of surfaceView

    //If you do not add f at the end of the float type number, a compile error will occur.
    static final float RADIUS = 150.0f;     //A constant that represents the radius when drawing a ball(The unit is pixel)
    static final int DIA = (int)RADIUS * 2; //A constant representing the diameter of the ball(Cast to int type)
    static final float COEF = 1000.0f;      //Coefficient for adjusting the amount of movement of the ball

    float mBallX;           //The current X coordinate of the ball(position)
    float mBallY;           //The current Y coordinate of the ball(position)
    float mVX;              //Acceleration of the ball in the X-axis direction
    float mVY;              //Acceleration of the ball in the Y-axis direction

    //long is a class for representing time
    long mT0;               //The time when the acceleration was acquired from the sensor last time

    //Bitmap is a class for handling images
    Bitmap mBallBitmap;     //Image of the ball

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //Fixed screen to vertical display
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        setContentView(R.layout.activity_main);

        /* getSystemService=>Use the android system.
SENSOR in its argument to use the sensor_Use SERVICE.
Store the returned SensorManager in the member variable mSensorManager*/
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        /*TYPE representing the accelerometer in the argument of the getDefaultSensor method_Specify ACCELEROMETER
Stored in member variable mAccSensor*/
        mAccSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        //Get the surfaceView placed in the screen layout and store it in the member variable mHolder
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        mHolder = surfaceView.getHolder();

        //Event listener when surfaceHolder is changed / destroyed
        mHolder.addCallback(this);

        //Since the background image is prepared, make the canvas itself transparent
        mHolder.setFormat(PixelFormat.TRANSLUCENT);
        surfaceView.setZOrderOnTop(true);

        //Show image of the ball
        // decodeResource()Get resources with method
        //GetResources as an argument()Can be obtained by specifying the id of the method and resource
        Bitmap ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
        //Resize the drawn ball
        //DIA the vertical height of the resource acquired in the above line and stored in the ball with createScaledBitmap(diameter)、
        //Specify the left and right length as DIA
        //The last argument is a filter(Correction for pixel jaggedness)Whether or not to apply
        mBallBitmap = Bitmap.createScaledBitmap(ball, DIA, DIA, false);
    }

    //Method called when the value of the accelerometer changes
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {

        //If the sensor is an accelerometer
        if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

            /*X the acceleration obtained from the sensor,Substitute for y
Invert the x-axis to match the drawing direction of the screen
It should be noted that each acceleration is understood as an acceleration in the x-axis direction and an acceleration in the y-axis direction.
When accelerating in the opposite direction, it seems that the value will be negatively multiplied.*/
            float x = -sensorEvent.values[0];
            float y = sensorEvent.values[1];

            /*Find time t
At the very beginning of the loop, the last time cannot be taken, so the timestamp of sensorEvent is assigned to mT0.*/
            if (mT0 == 0) {
                mT0 = sensorEvent.timestamp;
                // return;End with
                return;
            }

            //You can find the time by subtracting mT0, which contains the previous time, from the timestamp of the new sensorEvent.
            float t = sensorEvent.timestamp -mT0;
            mT0 = sensorEvent.timestamp;
            t = t/ 1000000000.0f;               //Convert nanoseconds to seconds

            //Find the distance traveled in the x and y directions
            //The following is a physics formula and you don't have to remember it
            // (Acceleration in the X-axis direction*time)+(Acceleration of x obtained from the sensor*timeの2乗を2で割る)And calculate the distance traveled
            float dx = (mVX * t) + (x * t * t/2.0f);
            // (Acceleration in the Y-axis direction*time)+(Acceleration of y obtained from the sensor*timeの2乗を2で割る)And calculate the distance traveled
            float dy = (mVY * t) + (y * t * t/2.0f);

            //Update the current ball position from the distance traveled
            //COEF is a coefficient for natural movement on the screen
            mBallX = mBallX + dx * COEF;
            mBallY = mBallY + dy * COEF;

            //Updated current ball movement speed(Constant acceleration motion formula<=Don't force yourself to remember)
            //speed=Initial velocity+acceleration*time
            mVX = mVX + (x * t);
            mVY = mVY + (y * t);

            //Processing to prevent the ball from going off the screen(First, the horizontal axis)
            //It becomes negative when the radius of the ball is subtracted from the x coordinate of the current position of the ball.(=Hitting the wall)
            //And if the speed is negative, reverse the speed and make it positive.
            if(mBallX - RADIUS < 0 && mVX < 0){
                //Hit the wall and slow down(Speed 1.Divide by 5 to slow down)
                mVX = -mVX / 1.5f;
                //Update the ball position coordinates to the radius value
                mBallX = RADIUS;
                //If the sum of the x-coordinate and radius of the ball is larger than the width of the surfaceView and the velocity is 0 or more
                // =If it goes off the screen in the opposite direction
            } else if (mBallX + RADIUS > mSurfaceWidth && mVX > 0){
                //Hit the wall and slow down
                mVX = -mVX / 1.5f;
                //The position of the ball to the value obtained by subtracting the radius from the width of surfaceVIew(X coordinate of)Update
                mBallX = mSurfaceWidth - RADIUS;
            }

            //Processing to prevent the ball from going off the screen(Next is the vertical axis)
            if(mBallY - RADIUS < 0 && mVY < 0){
                mVY = - mVY / 1.5f;
                mBallY = RADIUS;
            } else if (mBallY + RADIUS > mSurfaceHeight && mVY > 0){
                mVY = -mVY / 1.5f;
                mBallY = mSurfaceHeight - RADIUS;
            }

            //Redraw the ball on the canvas at the current position of the ball calculated from the acceleration
            drawCanvas();
        }
    }

    //The process of displaying the ball on the screen
    private void drawCanvas() {
        //When you call lockCanvas and get canvas, the surface is locked and you can draw it.
        Canvas c = mHolder.lockCanvas();
        //Clear the ball on the screen with drawColor(If you do not clear the previous drawing, the screen will be full of balls)
        //In other words, drawColor()Is a method of filling something with some color,
        //This time it means to fill the canvas with a transparent color.
        //The second argument is apparently required
        c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        //The Paint class is necessary to set elements for actual drawing such as drawing color, line thickness, character size and font.
        //This time just create an instance for the time being
        Paint paint = new Paint();
        //Coordinates of canvas canvas(left, top)Draw based on the position of
        c.drawBitmap(mBallBitmap, mBallX - RADIUS, mBallY - RADIUS, paint);

        //Member variable, mHolder, where surfaceView is stored(holder)Reflection on the screen and unlock of canvas
        mHolder.unlockCanvasAndPost(c);
    }

    //A method called when the accuracy of the accelerometer changes
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    //Method called when the screen is displayed
    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    //Called when the Surface is created
    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        /*registerListener is a method to start monitoring the accelerometer
First argument: Who monitors (this refers to MainActivity itself)
Second argument: Sensor you want to monitor
Third argument: Frequency you want to monitor*/
        mSensorManager.registerListener(this, mAccSensor, SensorManager.SENSOR_DELAY_GAME);
    }

    //Called when there is a change in the Surface
    //At the same time, initialize the position, speed, and time of the ball.
    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        mSurfaceWidth = i1;
        mSurfaceHeight = i2;

        //Specify the initial position of the ball
        //If you specify half the width and height of the surfaceView, you can place it in the center.
        mBallX = mSurfaceWidth / 2;
        mBallY = mSurfaceHeight / 2;

        //Initial speed and time initialization
        mVX = 0;
        mVY = 0;
        mT0 = 0;
    }

    //Called when the Surface is deleted
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        //End monitoring when the screen is closed//
        mSensorManager.unregisterListener(this);
    }
}

Try to run

image.png

To execute, click the> execute button on the upper right.

image.png Select an emulator. If you want to try it on an actual device, you need to make settings on the actual device before connecting the actual device via USB (omitted). image.png

If you select "..." at the bottom right and then select Virtual sensors image.png You can tilt the emulator and play like this

About small bounds

If you try running the emulator, you can see that it works according to the sensor. However, since the bound processing is performed but the stop processing is not performed, the ball continues to bounce little by little even if the emulator is fixed. It's a specification, not a bug.

There seems to be a way to set a threshold at the deceleration process and set the acceleration to 0 to stop it completely.

I will try it when I get a little better understanding.

Recommended Posts

[Beginner] android app that rolls a ball using a sensor [Java]
Ssh connect using SSHJ from a Java 6 app
Create a portfolio app using Java and Spring Boot
Create a docker image that runs a simple Java app
Make a rhombus using Java
[Android] Create a calendar using GridView
I made a shopify app @java
Upload a file using Java HttpURLConnection
Create a Java project using Eclipse
I made a matching app (Android app)
[Android] I made a pedometer app.
A standalone Java app that sends logs to CloudWatch Logs with slf4j / logback
Java beginner tried to make a simple web application using Spring Boot
Consolidate your JavaFX app into a jar that runs on both Java 8/11
[Rails6] Create a new app with Rails [Beginner]
Sobel filter using OpenCV on Android (Java)
Create a TODO app in Java 7 Create Header
Try making a calculator app in Java
Deploy a Java web app on Heroku
I made a calculator app on Android
[Rails 5] Create a new app with Rails [Beginner]
I made a rock-paper-scissors app with android
A memo that touched Spring Boot
MVC model
A simple example of an MVC model
[Personal memo] I learned a little about modifiers
A story that separates business logic and model
A memo for myself that object-oriented is something
A memo that handles a class created independently with ArrayList
What is MVC model?
[Beginner] android app that rolls a ball using a sensor [Java]
[Azure] I tried to create a Java application for free-Web App creation- [Beginner]