dir.by  
  Поиск  
Программирование, разработка, тестирование
Android, Google Play телефон, планшет (пишем приложение, игру)
C++ игра (для Android телефона) в Android Studio | Android NDK, OpenGL ES
Создаем проект "Android Native C++ Game" для телефона | Android Studio, Android NDK, OpenGL ES, C++
  Посмотрели 21286 раз(а)       Комментариев 1  
 Последний комментарий: (8 июня 2023 14:35) Good читать...       написать комментарий...
 Создаем проект "Android Native C++ Game" для телефона | Android Studio, Android NDK, OpenGL ES, C++ 
последнее обновление: 18 марта 2024
 
Что может этот проект "Android Native C++ Game"?                  обновлено 17 марта 2024 года
Этот проект содержит только C++ код и код минимальный.
Отрисовывает экран 50 раз в секунду используя OpenGL
Работает на старом планшете, телефоне с версией Android 4 (это версия вышла в 2011 году)
Проект очень очень простой. Содержит 4 файла:

main.cpp ... со 150 строками Android системного кода (инициализация устройства, получение фокуса, устранение фокуса, обработка событий использования, таких как касание пальца, перемещение). Этот файл main.cpp законченный и не надо его редактировать (если сильно хотите то можете).
 
graphic.cpp ... со 180 строками кода OpenGL (инициализируем поверхность OpenGL, закрываем OpenGL, реализован класс MyPolygon для рисования соединяемых линий с цветом заливки внутри). Этот файл graphic.cpp законченный и не надо его редактировать (если сильно хотите то можете).
 
my_game.cpp ... с 90 строчками кода: это указание координат моего самолета, вражеских самолетов в начале игры, указание координат деревьев, озера. Движение камеры. Обработка нажимания на экран и перемещение моего самолета влево, вправо.
 
my_game_assets.h ... 130 строчек: тут только координаты точек и цвета для моего самолета, вражеского самолета, озера, дерева. Векторная графика рисовалась в Adobe Illustrator и экспортировалась в SVG файлы и из SVG файлов я копировал сюда точки и цвета.
 
это приложение использует Android NDK ( это системная C++ библиотека для Android телефона) ... и поэтому работает очень быстро
это приложение использует OpenGL ES ( это C++ графическая библиотека для Android телефона) ... и поэтому рисует 2D и 3D графику очень быстро
Этот проект не использует большую Google библиотеку Android Games Development Kit ....
Этот проект не содержит Java код.
Шаг 1. Скачиваем проект "Android Native C++ Game"
Скачать с github.com:
В Google Chrome открываем github.com/EvgenProjects/AndroidNative_BasicGame
Github проект "Android Native C++ Game" для телефона |  Android Studio  Android NDK  OpenGL ES  C++
Github проект "Android Native C++ Game" для телефона | Android Studio, Android NDK, OpenGL ES, C++
Шаг 2. Открываем проект "Android Native C++ Game" в Android Studio
Если у вас не установлена Android Studio, то нужно: Скачайте и установите Android Studio для Windows 10 ...
Открываем Android Studio
 
Нажимаем Open.
Выбираем путь к скаченному проекту:
 
Прошло 2 минуты.
Проект полностью загрузился:
Шаг 3. Запускаем проект
 
[1] Выбираем Android виртуальное устройство
   Я использую "My Nexus 5 API 27" создал свое виртульное устройство Android ...

[2] Запускаем проект
   Для запуска нажимаем в меню RunRun 'app'.

[3] Выбираем вкладку Emulator
   чтобы видеть эмулятор телефона

[4] Смотрим результат внутри эмулятора телефона.
Шаг 4. Смотрим файлы проекта и объяснение                  обновлено 17 марта 2024 года
D:\ndk-samples-master\native-activity
        build.gradle
        gradle.properties
        gradlew
        gradlew.bat
        settings.gradle
        gradle
                wrapper
                        gradle-wrapper.jar
                        gradle-wrapper.properties
        app
                build.gradle
                src
                        main
                                AndroidManifest.xml
                                cpp
                                        CMakeLists.txt
                                        main.cpp
                                        graphic.cpp
                                        graphic.h
                                        my_game.cpp
                                        my_game.h
                                        my_game_assets.h
                                res
                                        mipmap-hdpi
                                                ic_launcher.png
                                        mipmap-mdpi
                                                ic_launcher.png
                                        mipmap-xhdpi
                                                ic_launcher.png
                                        mipmap-xxhdpi
                                                ic_launcher.png
                                        values
                                                strings.xml
 
←       
←       
←       
←        НЕ РЕДАКТИРОВАТЬ эти gradle файлы
←        Эти gradle файлы используются для сборки проекта в Android
←        эти gradle файлы одинаковые для всех проектов
←        
←       
←       
 
  build.gradle         файл для указания версии Android. Этот файл можем менять
 

  AndroidManifest.xml     файл в котором указываем Activity в проекте. Этот файл можем менять
 
  CMakeLists.txt         в этом файле описываем наши cpp файлы для компиляции. Этот файл можем менять
  main.cpp                   в этом файле мы пишем код на языке C++. Этот файл можем менять
  graphic.cpp            в этом файле мы пишем код на языке C++. Этот файл можем менять
  graphic.h            в этом файле мы пишем код на языке C++. Этот файл можем менять
  my_game.cpp            в этом файле мы пишем код на языке C++. Этот файл можем менять
  my_game.h              в этом файле мы пишем код на языке C++. Этот файл можем менять
  my_game_assets.h           в этом файле мы пишем код на языке C++. Этот файл можем менять
  

   ic_launcher.png
  
   ic_launcher.png
  
   ic_launcher.png
 
   ic_launcher.png
 
  strings.xml содержит текст "Android Native C++ Game"     

обновлено 17 марта 2024 года
Файл build.gradle
apply plugin: 'com.android.application'

android {
     compileSdkVersion 30
     ndkVersion '22.1.7171670'

     defaultConfig {
          applicationId = 'com.game.my_native_activity'
          minSdkVersion 14
          targetSdkVersion 31
          externalNativeBuild {
               cmake {
                    arguments '-DANDROID_STL=c++_static'
               }
          }
     }
     buildTypes {
          release {
               minifyEnabled false
               proguardFiles getDefaultProguardFile('proguard-android.txt'),
                         'proguard-rules.pro'
          }
     }
     externalNativeBuild {
          cmake {
               version '3.18.1'
               path 'src/main/cpp/CMakeLists.txt'
          }
     }
}

dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
}
Описание:
 
 
  
 
 
 
 
 
minSdkVersion 14   указали минимальную версию Android SDK.
Android SDK это эмулятор(копия) операционной системы Android.
Android SDK 14 соответствует операционной системе Android 4 (вышла в 2011 году)
То есть в 2011 году я купил планшет.
На планшете стояла операционная система Android 4.
Я указал minSdkVersion 14 в этом файле это значит, что на моем древнем планшете эта программа должна заработать.

 
 
 
 
 
externalNativeBuild
    path 'src/main/cpp/CMakeLists.txt'   указали что используем CMakeLists.txt
CMakeLists.txt используется для компиляции cpp файлов.
Файл AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.game.my_native_activity"
     android:versionCode="1"
     android:versionName="1.0">

     <application
 
         android:allowBackup="false"
          android:fullBackupContent="false"
          android:icon="@mipmap/ic_launcher"
          android:label="@string/app_name"
          android:hasCode="true">

          <!-- activity -->
          <activity
               android:name="android.app.NativeActivity"
               android:configChanges="orientation|keyboardHidden"
               android:exported="true">

               <!-- activity will be extended with C++ library: MyCPlusPlusActivity -->
               <meta-data
                    android:name="android.app.lib_name"
                    android:value="MyCPlusPlusActivity"
               />

               <intent-filter>
                    <action android:name="android.intent.action.MAIN" ></action>
                    <category android:name="android.intent.category.LAUNCHER"></category>
               </intent-filter>
 
          </activity>
     </application>

</manifest>
Описание:
 
 


 

 


android:icon="@mipmap/ic_launcher"       Иконка для приложения. Берется из ресурсов
android:label="@string/app_name"        Название приложения. Берется из ресурсов
 
<activity                     Описываем активность. Активность это экран
android:name="android.app.NativeActivity"
android.app.NativeActivity это зарезервированное слово то есть название активности из библиотеки Android.
Если не использовать NDK, то имя активности будет имя нашего Java класса. Вот так: android:name=".MainActivity". А MainActivity это Java класс.

<meta-data
android:name="android.app.lib_name"    android.app.lib_name это значит ниже будем указывать название C++ библиотеки для активности
 
android:value="MyCPlusPlusActivity"    название C++ библиотеки для активности
/>

</activity>
Файл CMakeLists.txt
#
# Copyright (C) The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

cmake_minimum_required(VERSION 3.4.1)

# build native_app_glue as a static lib
set(${CMAKE_C_FLAGS}, "${CMAKE_C_FLAGS}")
add_library(native_app_glue STATIC
     ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)

# now build app's shared lib
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -Werror")

# Export ANativeActivity_onCreate(),
# Refer to: https://github.com/android-ndk/ndk/issues/381.
set(CMAKE_SHARED_LINKER_FLAGS
     "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")

add_library(MyCPlusPlusActivity
          SHARED
          main.cpp
          graphic.cpp
          my_game.cpp)
 
 
 
target_include_directories(MyCPlusPlusActivity PRIVATE
     ${ANDROID_NDK}/sources/android/native_app_glue)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  
 
 
 
# add lib dependencies
target_link_libraries(MyCPlusPlusActivity
     android
     native_app_glue
     EGL
     GLESv1_CM
     log)
Описание:
 
 
 
  
  
  
  

  
 
 
 
 

 
 

 
 
 
 
 
 
 
 
 
 
 
add_library(MyCPlusPlusActivity    при компиляции будет создана библиотека (файл) с именем MyCPlusPlusActivity
main.cpp         добавили свой файл
graphic.cpp         добавили свой файл
my_game.cpp         добавили свой файл
 
 
 
target_include_directories( MyCPlusPlusActivity    В Android Studio проекте автоматически покажутся файлы из папки ${ANDROID_NDK}/sources/android/native_app_glue:

 
 
target_link_libraries(MyCPlusPlusActivity    добавляем системные библиотеки:
android
native_app_glue
EGL
GLESv1_CM        это OpenGL ES 1.0
log
 
Файл main.cpp
#include <android_native_app_glue.h>
#include <android/sensor.h>
#include <cassert>

#include "my_game.h"

// my settings
class MySettings
{
     // fields
     public: constexpr static const float TURN_TIMES_IN_SECONDS = 0.02f; // 50 times per second
     public: bool m_IsPause = false;
     public: MyGame MyGame;

     // local variables
     private: struct timespec _currentTime;
     private: struct timespec _lastTime;

     // constructor
     public: MySettings(AAssetManager* pAssetManager) : MyGame(pAssetManager)
     {
          _currentTime.tv_sec = 0;
          _currentTime.tv_nsec = 0;
          _lastTime.tv_sec = 0;
          _lastTime.tv_nsec = 0;
     }

     public: bool IsNextGameTick()
     {
          // get current time
          _currentTime.tv_sec = _currentTime.tv_nsec = 0;
          clock_gettime(CLOCK_MONOTONIC, &_currentTime);

          // is ellapsed time
          if ( ((_currentTime.tv_sec - _lastTime.tv_sec) + (_currentTime.tv_nsec - _lastTime.tv_nsec) / 1000000000.f) >= TURN_TIMES_IN_SECONDS )
          {
               // set last time
               _lastTime.tv_sec = _currentTime.tv_sec;
               _lastTime.tv_nsec = _currentTime.tv_nsec;
               return true;
          }
          return false;
     }
};

/**
* touch events:
*/

int32_t engine_handle_input(struct android_app* app, AInputEvent* pEvent)
{
     MySettings* pMySettings = (MySettings*)app->userData;

     bool isMotion = AInputEvent_getType(pEvent) == AINPUT_EVENT_TYPE_MOTION;
     bool isTouchDown = (AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction(pEvent)) == AMOTION_EVENT_ACTION_DOWN;
     bool isTouchUp = (AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction(pEvent)) == AMOTION_EVENT_ACTION_UP;
     float xDevicePixel = AMotionEvent_getX(pEvent, 0);
     float yDevicePixel = AMotionEvent_getY(pEvent, 0);

     return pMySettings->MyGame.OnHandleTouch(pEvent, isMotion, isTouchDown, isTouchUp, xDevicePixel, yDevicePixel);
}

/**
* application events: application on focus, lost focus, window create, window close
*/

void engine_handle_cmd(struct android_app* app, int32_t cmd)
{
     MySettings* pMySettings = (MySettings*)app->userData;

     switch (cmd) {
          case APP_CMD_SAVE_STATE:
               break;

          case APP_CMD_INIT_WINDOW:
               pMySettings->MyGame.OnCreateWindow(app->window);
               break;

          case APP_CMD_TERM_WINDOW:
               pMySettings->MyGame.OnKillWindow();
               break;

          case APP_CMD_GAINED_FOCUS:
          {
               pMySettings->m_IsPause = false;
               pMySettings->MyGame.OnActiveFocus();
               break;
          }

          case APP_CMD_LOST_FOCUS:
          {
               pMySettings->m_IsPause = true;
               pMySettings->MyGame.OnLostFocus();
               break;
          }

          default:
               break;
     }
}

/**
* This is the main entry point of a native application that is using android_native_app_glue.
* It runs in its own thread, with its own event loop for receiving input events and draw scene.
*/

void android_main(struct android_app* pAndroidApp)
{
     MySettings mySettings(pAndroidApp->activity->assetManager);

     pAndroidApp->userData = &mySettings;
     pAndroidApp->onAppCmd = engine_handle_cmd;
     pAndroidApp->onInputEvent = engine_handle_input;

     // events.
     int ident;
     int events;
     struct android_poll_source* source;

     // loop waiting for stuff to do.
     while (true)
     {
          // If -1, we will block forever waiting for events.
          // If 0, we loop until all events are read, then continue to draw the next frame of animation.
          if ((ident = ALooper_pollOnce(0 /* -1 0 */, nullptr, &events,(void**)&source)) >= 0)
          {
               // Process this event.
               if (source != nullptr) {
                    source->process(pAndroidApp, source);
               }

               // stop application
               if (pAndroidApp->destroyRequested != 0)
               {
                    mySettings.MyGame.OnKillWindow();
                    return;
               }
          }

          if (!mySettings.m_IsPause)
          {
               // draw scene
               mySettings.MyGame.OnDraw();

               // next tick
               if (mySettings.IsNextGameTick())
               {
                    mySettings.MyGame.OnNextTick();
               }
          }
     }
}
Описание:

В этом файле мы обрабатываем события телефона, рисуем, пересчитываем следующий ход 50 раз в секунду.

Этот файл содержит C++ методы и их можно менять:

engine_handle_input(...)                Обработка сенсорных событий

engine_handle_cmd(...)                Обработка событий приложения: приложение в фокусе, потеря фокуса, создание окна, закрытие окна

android_main(...)                Точка входа при запуске приложения
Файл my_game.cpp
#include <android/native_window.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include "my_game.h"
#include "my_game_assets.h"

MyGame::MyGame(AAssetManager* pAssetManager)
{
     m_pAssetManager = pAssetManager;
     m_isButtonPressed = false;
     m_2DcameraPosition.x = 0;
     m_2DcameraPosition.y = 0;
}

void MyGame::OnActiveFocus()
{
}

void MyGame::OnLostFocus()
{
}

bool MyGame::OnHandleTouch(AInputEvent* pEvent, bool isMotion, bool isTouchDown, bool isTouchUp, float xDevicePixel, float yDevicePixel)
{
     if (isMotion && isTouchDown)
     {
          m_isButtonPressed = true;
          m_ptInDevicePixelWhenTouched = XY(xDevicePixel, yDevicePixel);
          return true;
     }
     else if (isMotion && isTouchUp)
     {
          m_isButtonPressed = false;
          return true;
     }
     return false; // event not handled
}

void MyGame::OnNextTick()
{
     m_2DcameraPosition.y -= 0.008;

     for (int i=0; i<m_arrEnemyAirPlane.size(); i++)
          m_arrEnemyAirPlane[i].MoveByOffset(0, -0.004);

     if (m_isButtonPressed)
     {
          if (m_ptInDevicePixelWhenTouched.x < m_Graphic.GetWidth()/2.0f)
               m_MyAirPlane.MoveByOffset(-0.008, 0);
          else
               m_MyAirPlane.MoveByOffset(0.008, 0);
     }
}

void MyGame::OnDraw()
{
     m_Graphic.DrawBackground(0.72f, 0.87f, 0.55f, 1);

     // no move
     glLoadIdentity();
     glTranslatef(0, 0, 0);
     m_MyAirPlane.Draw();

     // move camera
     glLoadIdentity();
     glTranslatef(m_2DcameraPosition.x, m_2DcameraPosition.y, 0);

     for (int i=0; i<m_arrEnemyAirPlane.size(); i++)
          m_arrEnemyAirPlane[i].Draw();

     for (int i=0; i<m_arrBackgroundObject.size(); i++)
          m_arrBackgroundObject[i].Draw();

     m_Graphic.DrawGraphicEnd();
}

void MyGame::OnKillWindow()
{
     m_Graphic.CloseGraphic();
}

void MyGame::OnCreateWindow(ANativeWindow *pWindow)
{
     m_Graphic.InitGraphic(pWindow);

     m_2DcameraPosition.x = 0;
     m_2DcameraPosition.y = 0;

     m_MyAirPlane = TEMPLATE_MyAirPlane.CreateByTemplate(XY(0.5, 0.8), 0.2, 0.1);
     m_arrEnemyAirPlane.push_back(TEMPLATE_EnemyAirPlane.CreateByTemplate(XY(0.1, -1.4), 0.2, 0.1));
     m_arrEnemyAirPlane.push_back(TEMPLATE_EnemyAirPlane.CreateByTemplate(XY(0.15, -1.8), 0.2, 0.1));

     m_arrBackgroundObject.push_back(TEMPLATE_Lake.CreateByTemplate(XY(0.4, -1.3), 0.5, 0.5));
     m_arrBackgroundObject.push_back(TEMPLATE_Tree.CreateByTemplate(XY(0.88, -0.9), 0.08, 0.06));
     m_arrBackgroundObject.push_back(TEMPLATE_Tree.CreateByTemplate(XY(0.9, -1.2), 0.08, 0.06));
     m_arrBackgroundObject.push_back(TEMPLATE_Tree.CreateByTemplate(XY(0.3, -1.3), 0.08, 0.06));
}
Описание:

В этом файле мы должны делать всю логику.
Сейчас в этом файле я создаю объекты: свой самолет, вражеские самолеты, деревья, озеро.

Этот файл содержит C++ методы и их нужно менять:

MyGame::MyGame(AAssetManager* pAssetManager)
{
...
}

void MyGame::OnActiveFocus()
{
...
}

void MyGame::OnLostFocus()
{
...
}

bool MyGame::OnHandleTouch(AInputEvent* pEvent)
{
...
}

void MyGame::OnNextTick()
{
...
}

void MyGame::OnDraw()
{
...
}

bool MyGame::OnKillWindow()
{
...
}

void MyGame::OnCreateWindow(ANativeWindow* pWindow)
{
...
}
Файл my_game.h
#include <android/input.h>
#include <android/asset_manager.h>
#include <EGL/egl.h>
#include "graphic.h"

class MyGame
{
     // constructor
     public: MyGame(AAssetManager* pAssetManager);

     // fields
     protected: AAssetManager* m_pAssetManager;
     protected: MyGraphic m_Graphic;
     protected: bool m_isButtonPressed;
     protected: XY m_ptInDevicePixelWhenTouched;
     protected: float m_moveStep;

     // my game
     protected: MyObject m_MyAirPlane;
     protected: std::vector<MyObject> m_arrEnemyAirPlane;
     protected: std::vector<MyObject> m_arrBackgroundObject;
     protected: XY m_2DcameraPosition;

     // events
     public: void OnActiveFocus();
     public: void OnLostFocus();
     public: bool OnHandleTouch(AInputEvent* pEvent, bool isMotion, bool isTouchDown, bool isTouchUp, float xDevicePixel, float yDevicePixel);
     public: void OnNextTick();
     public: void OnCreateWindow(ANativeWindow* pWindow);
     public: void OnKillWindow();
     public: void OnDraw();
};
Файл my_game_assets.h
#include <EGL/egl.h>

#define colorBlue RGBA{0.0f, 0.0f, 0.7f, 0.8f}
#define colorLightBlue RGBA{0.0f, 0.0f, 0.5f, 0.7f}
#define colorWhite RGBA{0.9f, 0.9f, 0.9f, 1.0f}
#define colorVeryLightBlue RGBA{0.3f, 0.4f, 0.8f, 0.7f}

MyObject TEMPLATE_Lake = MyObject({

MyPolygon(GL_TRIANGLE_FAN, { // lake (points from Adobe Illustrator)
     {XY(50,50), colorLightBlue}, // center point
     {XY(43,0), colorBlue}, // first point
     {XY(68,2), colorBlue},
     {XY(85,10), colorBlue},
     {XY(94,23), colorBlue},
     {XY(100,36), colorBlue},
     {XY(100,64), colorBlue},
     {XY(84,88), colorBlue},
     {XY(59,100), colorBlue},
     {XY(41,100), colorBlue},
     {XY(19,94), colorBlue},
     {XY(4,75), colorBlue},
     {XY(1,50), colorBlue},
     {XY(5,27), colorBlue},
     {XY(14,10), colorBlue},
     {XY(43,0), colorBlue}, // first point
}),

});

MyObject TEMPLATE_MyAirPlane = MyObject({

     MyPolygon(GL_TRIANGLE_FAN, { // cabin (points from Adobe Illustrator)
          {XY(50, 14), colorLightBlue}, // center point
          {XY(48, 6), colorBlue}, // first point
          {XY(53, 6), colorBlue},
          {XY(56, 10), colorBlue},
          {XY(56, 20), colorBlue},
          {XY(44, 20), colorBlue},
          {XY(44, 10), colorBlue},
          {XY(48, 6), colorBlue}, // first point
     }),

     MyPolygon(GL_TRIANGLE_FAN, { // body (points from Adobe Illustrator)
          {XY(50,50), colorVeryLightBlue}, // center point
          {XY(41,10), colorVeryLightBlue}, // first point
          {XY(47,4), colorVeryLightBlue},
          {XY(54,4), colorVeryLightBlue},
          {XY(59,10), colorVeryLightBlue},
          {XY(55,93), colorWhite},
          {XY(45,93), colorWhite},
          {XY(41,10), colorVeryLightBlue}, // first point
     }),

     MyPolygon(GL_TRIANGLE_FAN, { // front wing (points from Adobe Illustrator)
          {XY(50,40), colorWhite}, // center point
          {XY(2,30), colorVeryLightBlue}, // first point
          {XY(98,30), colorVeryLightBlue},
          {XY(98,43), colorWhite},
          {XY(70,47), colorWhite},
          {XY(29, 47), colorWhite},
          {XY(2,43), colorWhite},
          {XY(2,30), colorVeryLightBlue}, // first point
     }),

     MyPolygon(GL_TRIANGLE_FAN, { // back wing (points from Adobe Illustrator)
          {XY(50,84), colorWhite}, // center point
          {XY(34,80), colorVeryLightBlue}, // first point
          {XY(66,80), colorVeryLightBlue},
          {XY(66,88), colorWhite},
          {XY(34,88), colorWhite},
          {XY(34,80), colorVeryLightBlue}, // first point
     }),
});

MyObject TEMPLATE_EnemyAirPlane = MyObject({

     // Cabin
     MyPolygon(GL_TRIANGLE_FAN, "#D10000", XY(50, 79),
"45.928,71.216 53.928,71.216 54.72,77.501 55.047,80.93 53.948,84.656 45.948,84.656 44.733,81.084 45.011,77.667"),

     // Gun_right_on_wing
     MyPolygon(GL_TRIANGLE_FAN, "#726658", XY(75, 75),
"72.636,71.216 72.636,77.438 79.303,77.438 79.303,71.344 "),

     // Gun_right_on_wing
     MyPolygon(GL_TRIANGLE_FAN, "#726658", XY(22, 75),
"18.386,71.216 18.386,77.438 25.053,77.438 25.053,71.344"),

     // Wing_back_right
     MyPolygon(GL_TRIANGLE_FAN, "#D10000", XY(60, 13),
"52.594,7.364 56,7.364 56,4.958 60.656,4.958 60.656,6.161 66.094,6.161 68.844,9.989 68.844,15.958 65.969,18.896 53.656,19.864"),

     // Wing_back_left
     MyPolygon(GL_TRIANGLE_FAN, "#D10000", XY(40, 13),
"47.219,7.208 44.052,7.208 44.052,4.375 38.719,4.375 38.719,5.792 34.886,5.792 30.886,9.708 30.886,15.542 32.219,18.542 46.552,20.042"),

     // Body
     MyPolygon(GL_TRIANGLE_FAN, "#726658", XY(50, 50),
"46.511,4.959 48.886,2.875 50.886,2.875 53.323,4.875 54.011,15.688 54.636,24.563"
" 55.636,44.75 56.448,51.875 56.948,69.5 58.011,71.125 58.011,78.813 59.073,80.813 59.073,85.375 57.323,87.375 56.886,89.563"
" 42.886,89.563 42.386,87.531 40.604,85.375 40.604,80.813 41.698,79.209 41.714,70.969 42.636,69.126 43.481,51.883 44.167,44.656"
" 44.979,24.75 45.677,16"),

     // BlackBody
     MyPolygon(GL_TRIANGLE_FAN, "#414042", XY(50, 60),
"38.698,75.25 41.448,77.438 58.011,77.438 60.261,75.625 59.636,49.125 56.323,46.219 43.448,46.219 39.698,49.125"),

     // Wings_Front
     MyPolygon(GL_TRIANGLE_FAN, "#D10000", XY(50, 60),
          "41.802,48.792 5.802,54.209 2.302,58.125 2.302,65.959 5.469,71.292"
                    " 37.886,75.042 61.136,75.042 95.053,70.959 98.219,67.459 98.219,59.709 94.469,53.959 58.553,48.792"),

     // Propeller_center
     MyPolygon(GL_TRIANGLE_FAN, "#414042", XY(50, 92),
          "47.386,88.375 47.386,94.375 49.479,97.125 50.386,97.125 51.995,94.281 51.995,88.375"),

     // Propeller_left
     MyPolygon(GL_TRIANGLE_FAN, "#414042", XY(40, 93),
          "47.823,92.75 31.636,92.75 31.636,93.938 33.636,95.75 40.604,95.75 45.261,93.688 47.823,93.625"),

     // Propeller_right
     MyPolygon(GL_TRIANGLE_FAN, "#414042", XY(61, 93),
          "51.636,93.688 67.823,93.688 67.823,92.5 65.823,90.688 58.854,90.688 54.198,92.75 51.636,92.813"),
});

MyObject TEMPLATE_Tree = MyObject({

     // Body
     MyPolygon(GL_TRIANGLE_FAN, "#7E4E35", XY(50, 83),
          "43.145,67.725 55.25,67.725 56.729,98.876 40.25,98.876 "),

     // Leaves
     MyPolygon(GL_TRIANGLE_FAN, "#619E5B", XY(52, 35),
          "8.187,21.838 7.687,18.922 8.52,15.797 12.104,12.547 16.937,11.047 17.979,8.755 "
                    " 20.02,6.38 22.687,4.63 26.604,4.213 28.729,3.047 31.437,2.213 34.687,2.213 37.937,3.213 40.104,4.838 43.187,3.463 46.979,2.213 "
                    " 49.854,2.713 53.813,4.963 56.188,3.63 59.979,2.422 63.229,2.713 66.563,4.255 68.938,6.63 69.688,9.922 73.354,9.963 "
                    " 76.729,11.005 79.563,12.755 81.646,15.797 84.729,15.922 87.438,16.797 90.063,18.505 91.896,20.088 93.646,23.38 93.188,27.547 "
                    " 94.479,29.463 96.938,31.255 97.813,32.713 98.396,35.506 98.188,37.756 96.063,41.006 96.813,43.297 97.104,45.963 96.271,47.797 "
                    " 93.688,49.962 91.146,50.837 89.479,52.838 87.479,54.129 86.979,55.129 85.771,57.088 83.854,59.297 79.938,60.172 79.313,61.963 "
                    " 77.438,63.588 76.646,65.547 75.188,67.588 72.479,69.254 70.146,69.879 68.563,70.797 64.521,71.504 60.979,70.422 57.688,72.004 "
                    " 54.313,73.213 52.396,73.213 39.813,73.213 32.771,69.547 31.438,66.172 25.063,65.547 22.021,62.754 18.896,59.588 15.313,58.504 "
                    " 12.688,54.422 12.438,49.13 8.854,47.756 3.896,43.422 3.604,39.172 6.271,35.463 2.854,33.005 1.604,29.505 3.646,24.588 "),
});
Файл graphic.cpp
#include <android/native_window.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <GLES2/gl2.h>
#include <string>
#include <sstream>
#include <iostream>
#include "graphic.h"

MyGraphic::MyGraphic()
{
     m_Width = 0;
     m_Height = 0;
     m_isGraphicInited = false;
}

void MyGraphic::DrawBackground(float red, float green, float blue, float alpha)
{
     if (m_Display == EGL_NO_DISPLAY || m_Surface == EGL_NO_SURFACE || m_Context == EGL_NO_CONTEXT)
          return;

     glClearColor(red, green, blue, alpha);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void MyGraphic::DrawGraphicEnd()
{
     if (m_Display == EGL_NO_DISPLAY || m_Surface == EGL_NO_SURFACE || m_Context == EGL_NO_CONTEXT)
          return;

     eglSwapBuffers(m_Display, m_Surface);
}

void MyGraphic::CreateSurfaceFromWindow(ANativeWindow* pWindow)
{
     const EGLint attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
                                   EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
                                   EGL_BLUE_SIZE, 8,
                                   EGL_GREEN_SIZE, 8,
                                   EGL_RED_SIZE, 8,
                                   EGL_NONE};
     EGLint format;
     EGLint numConfigs;

     eglChooseConfig(m_Display, attribs, &m_configOpenGL, 1, &numConfigs);

     eglGetConfigAttrib(m_Display, m_configOpenGL, EGL_NATIVE_VISUAL_ID, &format);

     m_Surface = eglCreateWindowSurface(m_Display, m_configOpenGL, pWindow, NULL);
}

void MyGraphic::InitGraphic(ANativeWindow* pWindow)
{
     if (m_isGraphicInited)
     {
          CreateSurfaceFromWindow(pWindow);
          eglMakeCurrent(m_Display, m_Surface, m_Surface, m_Context);
          return;
     }

     // init Display
     m_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglInitialize(m_Display, nullptr, nullptr);

     // init Surface
     CreateSurfaceFromWindow(pWindow);

     // init Context
     EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 1/*openGL version 1*/ ,EGL_NONE };
     m_Context = eglCreateContext(m_Display, m_configOpenGL, NULL, contextAttribs);

     if (eglMakeCurrent(m_Display, m_Surface, m_Surface, m_Context) == EGL_FALSE)
          return;

     EGLint w, h;
     eglQuerySurface(m_Display, m_Surface, EGL_WIDTH, &w);
     eglQuerySurface(m_Display, m_Surface, EGL_HEIGHT, &h);

     m_Width = w;
     m_Height = h;

     // Open GL states
     //glEnable(GL_CULL_FACE);
     glEnable(GL_DEPTH_TEST);
     glEnable(GL_TEXTURE_2D);

     // for alpha color (transparency)
     glEnable( GL_BLEND );
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

     // enable draw lines and colors
     glEnableClientState(GL_VERTEX_ARRAY);// allow to use glVertexPointer
     glEnableClientState(GL_COLOR_ARRAY); // allow to use glColorPointer

     m_isGraphicInited = true;
}

void MyGraphic::CloseGraphic()
{
     if (m_Display != EGL_NO_DISPLAY)
     {
          eglMakeCurrent(m_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

          if (m_Context != EGL_NO_CONTEXT) {
               eglDestroyContext(m_Display, m_Context);
          }

          if (m_Surface != EGL_NO_SURFACE) {
               eglDestroySurface(m_Display, m_Surface);
          }

          eglTerminate(m_Display);
     }

     m_Display = EGL_NO_DISPLAY;
     m_Context = EGL_NO_CONTEXT;
     m_Surface = EGL_NO_SURFACE;
}

// my polygon
MyPolygon::MyPolygon()
{
     m_DrawMode = 0;
}

MyPolygon::MyPolygon(int drawMode, std::vector<XYZ_RGBA> arrPoint)
{
     m_DrawMode = drawMode;
     for (int i=0; i<arrPoint.size(); i++)
          m_arrPositionColor.push_back(arrPoint[i]);
}

MyPolygon::MyPolygon(int drawMode, const char* textColorRGB, XY centerPoint, const char* textPoints)
{
     m_DrawMode = drawMode;

     // convert textColorRGB = "#BE1E2D" -> r(0..1), g(0..1), b(0..1)
     RGBA color;
     std::string stringColorRGB = textColorRGB;
     int hexMode = 16;
     color.red = strtol(stringColorRGB.substr(1, 2).c_str(), NULL, hexMode);
     color.red /= 255.0f;

     color.green = strtol(stringColorRGB.substr(3, 2).c_str(), NULL, hexMode);
     color.green /= 255.0f;

     color.blue = strtol(stringColorRGB.substr(5, 2).c_str(), NULL, hexMode);
     color.blue /= 255.0f;

     color.alpha = 1; // no alpha

     // split string by space
     std::string stringPoints = textPoints;
     std::istringstream f(stringPoints);
     std::string textPoint;
     while (std::getline(f, textPoint, ' '))
     {
          int pos = std::string(textPoint).find(',');
          XY position;
          position.x = atof(textPoint.substr(0, pos).c_str());
          position.y = atof(textPoint.substr(pos+1).c_str());

          m_arrPositionColor.push_back(XYZ_RGBA(position, color));
     }

     // add first point to end
     m_arrPositionColor.push_back(m_arrPositionColor[0]);

     // add center point at begin
     m_arrPositionColor.insert(m_arrPositionColor.begin(), XYZ_RGBA(centerPoint, color));
}

void MyPolygon::Draw()
{
     int countOfPointsToDraw = m_arrPositionColor.size();

     // point (x,y,z)
     glVertexPointer(3, // it is count of fields: x,y,z
                         GL_FLOAT,
                         sizeof(XYZ_RGBA),
                         (GLvoid*)m_arrPositionColor.data()
     );

     // color (r,g,b,alpha)
     glColorPointer(4, // it is count of fields: red,green,blue, alpha
                    GL_FLOAT,
                    sizeof(XYZ_RGBA),
                    (GLvoid*) ((char*)m_arrPositionColor.data()+sizeof(XYZ))
     );

     glDrawArrays(m_DrawMode, 0 /*first index to draw*/, countOfPointsToDraw);
}

void MyPolygon::MoveByOffset(float xOffset, float yOffset)
{
     for (int i=0; i<m_arrPositionColor.size(); i++) {
          m_arrPositionColor[i].position.x += xOffset;
          m_arrPositionColor[i].position.y += yOffset;
     }
}

/////////
MyObject::MyObject()
{}

MyObject::MyObject(std::vector<MyPolygon> arrPolygon)
{
     for (int i=0; i<arrPolygon.size(); i++)
          m_arrPolygon.push_back(arrPolygon[i]);
}

void MyObject::AddPolygon(MyPolygon myPolygon)
{
     m_arrPolygon.push_back(myPolygon);
}

void MyObject::Draw()
{
     for (int i=0; i<m_arrPolygon.size(); i++)
          m_arrPolygon[i].Draw();
}

void MyObject::MoveByOffset(float xOffset, float yOffset)
{
     for (int i=0; i<m_arrPolygon.size(); i++)
          m_arrPolygon[i].MoveByOffset(xOffset, yOffset);
}

MyObject MyObject::CreateByTemplate(XY realPos, float realWidth, float realHeight)
{
     MyObject resultObject;

     float minX = 0, maxX = 0;
     float minY = 0, maxY = 0;
     for (int iPolygon=0; iPolygon<m_arrPolygon.size(); iPolygon++)
     {
          MyPolygon myPolygon = m_arrPolygon[iPolygon];
          for (int i=0; i<myPolygon.ItemsCount(); i++)
          {
               XYZ_RGBA& rItem = myPolygon.GetItem(i);
               if (rItem.position.x<minX)
                    minX = rItem.position.x;
               if (rItem.position.x>maxX)
                    maxX = rItem.position.x;
               if (rItem.position.x<minY)
                    minY = rItem.position.y;
               if (rItem.position.x>maxY)
                    maxY = rItem.position.y;
          }
     }
     float imgWidth = maxX-minX;
     if (imgWidth<=0)
          return resultObject;

     float imgHeight = maxY-minY;
     if (imgHeight<=0)
          return resultObject;

     for (int iPolygon=0; iPolygon<m_arrPolygon.size(); iPolygon++)
     {
          MyPolygon myPolygon = m_arrPolygon[iPolygon];

          // convert each point
          for (int i=0; i<myPolygon.ItemsCount(); i++)
          {
               XYZ_RGBA& rItem = myPolygon.GetItem(i);
               XY pt = XY (
                         realPos.x + realWidth * rItem.position.x / imgWidth,
                         realPos.y + realHeight * rItem.position.y / imgHeight);

               // convert from 0..1 to -1 ... 1
               rItem.position.x = pt.x*2.f-1.f;
               rItem.position.y = 2.f*(1.f-pt.y)-1.f;
          }
          resultObject.AddPolygon(myPolygon);
     }
     return resultObject;
}
Описание:

Только в этом файле OpenGL графика.

В классе MyGraphic инициализация OpenGL графики.

В классе MyPolygon рисование полигона по точкам и закрашивание внутри.

В классе MyObject содержится коллекция MyPolygon. Например, когда я создаю самолет я создаю MyObject. Самолет содержит крыло это один полигон, тело еще один полигон, хвост это еще один полигон.
Файл graphic.h
#include <android/input.h>
#include <android/asset_manager.h>
#include <GLES/gl.h>
#include <vector>

struct RGBA
{
     GLfloat red; // [0...1]
     GLfloat green; // [0...1]
     GLfloat blue; // [0...1]
     GLfloat alpha; // [0...1]
};

struct XYZ
{
     GLfloat x;
     GLfloat y;
     GLfloat z;
     XYZ(float x=0, float y=0, float z=0) { this->x=x; this->y=y; this->z=z;}
};

struct XY
{
     float x;
     float y;
     XY(float x=0, float y=0) { this->x=x; this->y=y; }
};


struct XYZ_RGBA
{
     XYZ position;
     RGBA color;
     XYZ_RGBA(XY pos, RGBA color, GLfloat z=0) { this->position.x=pos.x; this->position.y=pos.y; this->position.z=z; this->color=color; }
     XYZ_RGBA(XYZ position, RGBA color) { this->position=position; this->color=color; }
};

class MyGraphic
{
     // constructor
     public: MyGraphic();

     // fields
     protected: AAssetManager* m_pAssetManager;
     protected: EGLDisplay m_Display = EGL_NO_DISPLAY;
     protected: EGLSurface m_Surface = EGL_NO_SURFACE;
     protected: EGLContext m_Context = EGL_NO_CONTEXT;
     protected: EGLConfig m_configOpenGL = nullptr;
     private: bool m_isGraphicInited = false;
     protected: int32_t m_Width;
     protected: int32_t m_Height;

     // OpenGL private
     private: void CreateSurfaceFromWindow(ANativeWindow* pWindow);

     // OpenGL
     public: void InitGraphic(ANativeWindow* pWindow);
     public: void CloseGraphic();
     public: void DrawBackground(float red, float green, float blue, float alpha);
     public: void DrawGraphicEnd();
     int GetWidth(){ return m_Width; }
     int GetHeight(){ return m_Height; }
};

class MyPolygon
{
     public: MyPolygon();
     public: MyPolygon(int drawMode, std::vector<XYZ_RGBA> arrPoint);
     MyPolygon(int drawMode, const char* textColorRGB, XY centerPoint, const char* textPoints);

     public: void Draw();
     public: void MoveByOffset(float xOffset, float yOffset);
     public: int ItemsCount() {return m_arrPositionColor.size();}
     public: XYZ_RGBA& GetItem(int i) {return m_arrPositionColor[i];}

     // points
     protected: int m_DrawMode;
     protected: std::vector<XYZ_RGBA> m_arrPositionColor;
};

class MyObject
{
     public: MyObject();
     public: MyObject(std::vector<MyPolygon> arrPolygon);

     public: void Draw();
     public: void MoveByOffset(float xOffset, float yOffset);
     public: MyObject CreateByTemplate(XY realPos, float realWidth, float realHeight);
     public: void AddPolygon(MyPolygon myPolygon);

     protected: std::vector<MyPolygon> m_arrPolygon;
};
 Рисую озеро как векторная графика в Adobe Illustrator. Беру координаты точек из Adobe Illustrator и добавляю в мою 2D игру на C++ OpenGL 
Я делаю 2D игру самолетик летит и хочу нарисовать воду или озеро.

В OpenGL можно рисовать используя тругольники вот так:
Шаг 1. Открываю Adobe Illustrator
Если у вас не установлена Adobe Illustrator CS5 нужно скачать и установить пробную версию Adobe CS5 Master Collection ...

Открываем Adobe Illustrator CS5:
Открываем Adobe Illustrator CS5 | Векторная графика
Открываем Adobe Illustrator CS5 | Векторная графика
Шаг 2. Создаем новое полотно 100 x 100 точек
Шаг 3. Рисуем озеро
Шаг 4. Прижимаем озеро к границам
Шаг 5. Берем все точки озера
Шаг 6. Добавил точки в проект
Добавил точки (воду) в свою игру для телефона Android Native C++ Game в Android Studio используя Android NDK, OpenGL ES, C++ ...

У меня в проекте Android Native C++ Game есть файл my_game_assets.h и в этом файле в переменной g_Lake:
• хранятся координаты точек и цвета в виде массива
• Режим соединения точек. Я использую GL_TRIANGLE_FUN.
 
Как OpenGL рисует?
Библиотеке OpenGL для рисования нужны точки и режим рисования.
Я использую режим GL_TRIANGLE_FUN и вот мои точки:
Я в массиве задал 16 точек:

центральная точка   XY(50, 50)
точка 1   XY(43, 0)
точка 2   XY(68, 2)
точка 3   XY(85, 10)
точка 4   XY(94, 23)
точка 5   XY(100, 36)
точка 6   XY(100, 64)
точка 7   XY(84, 88)
точка 8   XY(59, 100)
точка 9   XY(41, 100)
точка 10   XY(19, 94)
точка 11   XY(4, 75)
точка 12   XY(1, 50)
точка 13   XY(5, 27)
точка 14   XY(14, 10)
точка 1   XY(43, 0)
OpenGL по трем точкам сделает треугольник и закрасит внутри.
Режим GL_TRIANGLE_FUN сделает такие треугольники:
 
1-ый треугольник: Центральная точка, точка 1, точка 2
 
2-ой треугольник: Центральная точка, точка 2, точка 3
 
3-ий треугольник: Центральная точка, точка 3, точка 4
 
4-ый треугольник: Центральная точка, точка 4, точка 5
 
5-ый треугольник: Центральная точка, точка 5, точка 6

и т.д.
 Рисую вражеский самолетик как векторная графика в Adobe Illustrator. Беру координаты точек из Adobe Illustrator и добавляю в мою 2D игру на C++ OpenGL 
Я делаю 2D игру самолетик летит и хочу нарисовать вражеский самолетик.

В OpenGL можно рисовать используя тругольники вот так:
Шаг 1. Открываю Adobe Illustrator
Если у вас не установлена Adobe Illustrator CS5 нужно скачать и установить пробную версию Adobe CS5 Master Collection ...

Открываем Adobe Illustrator CS5:
Открываем Adobe Illustrator CS5 | Векторная графика
Открываем Adobe Illustrator CS5 | Векторная графика
Шаг 2. Создаем новое полотно 100 x 100 точек
Шаг 3. Рисуем вражеский самолетик
 
← Предыдущая тема
Что такое Android OpenGL ES для Android телефона? Это C++ графическая библиотека для Android телефона.
 
Следующая тема →
Рисование озера по точкам для 2D игры
 
Ваши Отзывы ... 1 комментариев
гость
8 июня 2023 14:35
   
Вашe имя
Ваш комментарий (www ссылки может добавлять только залогиненный пользователь)

  Объявления  
  Объявления  
 
Что такое операционная система Android? Какие номера версий были в Android
Что такое ARM процессоры? | Android
Что такое AndroidX?
Java приложение (для Android телефона) в Android Studio
Почему Android приложения пишутся на Java?
Скачать и установить Android Studio для написания программ для Android телефонов на языке Java, Kotlin
Открываем Android Studio на компьютере (Windows 10)
Создаем новый проект на Java с одной простой Activity в Android Studio (пишем программу для Android телефонов, планшетов) в Windows 10
Компиляция и запуск приложения в Android Studio на компьютере (Windows) в режиме эмулятора Android Device
Запуск приложения Android Studio в отладке на компьютере (Windows) в режиме эмулятора Android Device
Ошибка "error while waiting for device: the emulator process for ..... has terminated" при запуске приложения в Android Studio на компьютере (Windows) в режиме эмулятора Android Device
Ошибка "Error while waiting for device: Illegal char <*> at index 0: *.lock ..." при запуске приложения в Android Studio
Ошибка "AVD is already running ..." при запуске приложения в Android Studio
Ошибка "CMake "3.18.1" was not found in SDK, PATH, or by cmake.dir property" при компиляции проекта в Android Studio
Ошибка "Execution failed for task ":app:compressDebugAssets" при компиляции проекта в Android Studio
Все ошибки при запуске Android приложения
Что такое Android SDK (копия операционной системы Android)? Инсталлирование Android SDK 8.1 в Android Studio ...
Создаем Android виртуальное устройство в Android Studio
Установить HAXM
Activity в Android
Kotlin приложение (для Android телефона) в Android Studio
Скачать и установить Android Studio для написания программ для Android телефонов на языке Java, Kotlin
Создаем новый проект "Empty Views Activity" на Kotlin в Android Studio (пишем программу для Android телефонов, планшетов) в Windows 10
Компиляция и запуск Kotlin приложения в Android Studio на компьютере (Windows) в режиме эмулятора Android Device
Запуск Kotlin приложения в Android Studio в отладке на компьютере (Windows) в режиме эмулятора Android Device
Запуск и отладка Kotlin Android Studio приложения на моем телефоне через USB
Долгое ожидание при запуске Kotlin Android приложения. Вижу сообщение: "I/zygote:Waiting for a blocking GC ProfileSaver"
Создаем Android проект добавляем TextView и показываем значение на телефоне | Android телефон, Android Studio, Kotlin, Windows 10
Копирование данных в классе и объекта. Используем аттрибут @Parcelize и интрефейс Parcelable. | Kotlin | Android Studio
Ошибка "Class is not abstract and does not implement abstract member public abstract fun describeContents(): Int defined in android.os.Parcelable" | Kotlin | Android Studio | @Parcelize | Parcelable
Показываем окно с 2-мя кнопками: yes, no и не надо добавлять никаких resource, layout | Я вызываю функцию AlertDialog в Kotlin | Android Studio
Android Kotlin приложение делает фото на камеру и рисует в приложении | Android Studio | Kotlin
Android Kotlin выбираем фото из галереи и рисуем в приложении | Android Studio | Kotlin ...
getExternalFilesDir - функция, которая возвращает полный путь к внешнему каталогу, в который наше приложение может помещать постоянные файлы | Android Studio, Kotlin
getFilesDir - функция, которая возвращает полный путь к каталогу, в который наше приложение может поместить файлы | Android Studio, Kotlin
Как работать с файлами, media в Android? Что такое content Uri и file path. Отличие getExternalFilesDir и getFilesDir ... | Android Studio, Kotlin
Как сделать переменную в build.gradle файле и передать ее в манифест файл AndroidManifest.xml | Android Studio | Kotlin
Как сделать переменную в build.gradle файле и передать ее в Kotlin файл | Android Studio | Kotlin
Moshi (Преобразование текста json в объект класса) | десериализация на языке Kotlin | Android Studio
Moshi (Преобразование массива json в список объектов) | десериализация на языке Kotlin | Android Studio
Ошибка "Failed to find the generated JsonAdapter class for class com.example.androidkotlinapp1.MyBook" | Exception | Kotlin | Moshi | Android Studio
Ошибка "A problem occurred evaluating project ':app'. Caused by: CustomMessageMissingMethodException: Could not find method kapt() for arguments [com.squareup.moshi:moshi-kotlin-codegen:1.14.0]" | При компиляции Kotlin, Moshi проекта в Android Studio
Jetpack приложение (для Android телефона) в Android Studio | Kotlin
Что такое Jetpack для Android?
Создаем новый проект "Jetpack Compose" на Kotlin в Android Studio (пишем программу для Android телефонов, планшетов) в Windows 10
C++ игра (для Android телефона) в Android Studio | Android NDK, OpenGL ES
Что такое Android NDK для Android телефона? Это C++ библиотека для Android телефона.
Что такое Android OpenGL ES для Android телефона? Это C++ графическая библиотека для Android телефона.
Создаем проект "Android Native C++ Game" для телефона | Android Studio, Android NDK, OpenGL ES, C++
Рисование озера по точкам для 2D игры
Рисую вражеский самолетик как векторная графика в Adobe Illustrator. Беру координаты точек из Adobe Illustrator и добавляю в мою 2D игру на C++ OpenGL
Компиляция и запуск "Android Native C++ Game" в Android Studio на компьютере(Windows) в режиме эмулятора Android Device
Ошибка "[CXX1405] error when building with cmake using CMakeLists.txt: C build system [configure] failed while executing cmake.exe" при компиляции Android Native C++ приложения в Android Studio на компьютере (Windows)
Ошибка "ninja: error: rebuilding 'build.ninja': subcommand failed" при компиляции Android Native C++ приложения в Android Studio на компьютере (Windows)
Рисование треугольника с закрашиванием внутри в "Android Native C++ Game" для телефона | Android Studio, Android NDK, OpenGL ES v1, C++
Загрузка bmp файла из Assets и рисование текстур в "Android Native C++ Game" для телефона | Android Studio, Android NDK, OpenGL ES v2 (shader), C++
Как получить файл bmp, расположенный в Assets внутри файла apk? | Android Studio, NDK, C++
Как использовать альфа-прозрачность при отображении текстуры с помощью OpenGL? | Android Studio, OpenGL ES, NDK, C++
Почему glTexImage2D возвращает ошибку с кодом 1280 ? | Android Studio, OpenGL ES, NDK, C++
Что такое cpp и h файлы в C++? | Android Studio, NDK, C++
Как создать новый файл h и добавить в проект android NDK C++? | Android Studio, NDK, C++
Как создать новый файл cpp и добавить в проект android NDK C++? | Android Studio, NDK, C++, CMakeLists.txt
dynamic_cast в C++ (преобразование указателя в другой тип и проверка валидности во время выполнения) | Android Studio, NDK, C++
std::map<Key, Value> это набор ключей и значений в C++. | Android Studio, NDK, C++
Передаем функцию как параметр в функцию (callback) | C++ | Android Studio, NDK, C++
Как найти событие при повороте дисплея (изменении ориентации) в телефоне Android | Android Studio, NDK, C++
Как обрабатывать события в телефоне Android (создание/завершение события окна, установка фокуса, потеря фокуса, касание в телефоне) | Android Studio, NDK, C++
Создаем подписанный apk файл в Android Studio | Android NDK, OpenGL ES
Google Play Console (для разработчика)
Создаем Google Play account разработчика | Google Play Console
Разработчику в Google Play Console требуется подтвердить личность | Google Play Console
Разработчик в Google Play Console должен подтвердить аккаунт разработчика | Google Play Console
Учетная запись разработчика не используется | Учетная запись разработчика находится под угрозой закрытия | Google Play Console
Скомпилируйте приложение и отправьте его в продакшн в Google Play Console | Мое приложение в Google Play Console
Policy status "App must target Android 15 (API level 35) or higher" | Status "You won't be able to release app updates" | Мое приложение в Google Play Console
Policy status "App must target Android 14 (API level 34) or higher" | Status "You won't be able to release app updates" | Мое приложение в Google Play Console
Создаем приложение в Google Play Console (в опции выбираю что это будет игра) | Моя игра в Google Play Console
Важные параметры: package, applicationId, versionCode, versionName, android:label (в AndroidManifest.xml, build.gradle) чтобы создать тестовую версию для Google Play Console | Моя игра в Google Play Console
Создаем подписанный .aab файл в Android Studio | Моя игра в Google Play Console
Компилируем игру и присылаем на внутреннее тестирование в Google Play Console | Моя игра в Google Play Console
Google автоматически запустил тесты и сделал картинки, отчет как запускается игра на разных марках телефонах | Моя игра в Google Play Console
Как задать Google Play Developer Console вопрос в поддержку?
Google Play Developer Console support feedback
Темы про Google Play Billing & in-app purchase | Google Play Console
Можно использовать (интегрировать) платежи в моей Google игре если я разработчик из Беларуси? | Монетизация в Google Play Console
Как изменить язык Google Play Console? | Google Chrome
Как изменить страну в платежном профиле? | Google Play Console
Как в Google Play посмотреть(открыть) платежную страницу? | Google Play Console

  Ваши вопросы присылайте по почте: info@dir.by  
Яндекс.Метрика