Как да напишете първата си игра на Android на Java

Автор: John Stephens
Дата На Създаване: 1 Януари 2021
Дата На Актуализиране: 19 Може 2024
Anonim
Создание многопоточного клиент-серверного приложения на Java
Видео: Создание многопоточного клиент-серверного приложения на Java

Съдържание


Има много начини да създадете игра за Android и един важен начин е да го направите от нулата в Android Studio с Java. Това ви дава максимален контрол върху това как искате вашата игра да изглежда и да се държи и процесът ще ви научи на умения, които можете да използвате и в редица други сценарии - независимо дали създавате екран за пръскане за приложение или просто искате да добавете някои анимации. Имайки това предвид, този урок ще ви покаже как да създадете проста 2D игра с помощта на Android Studio и Java. Можете да намерите всички кодове и ресурси в Github, ако искате да следвате.

Настройвам

За да създадем нашата игра, ще трябва да се справим с няколко конкретни понятия: игрални контури, конци и платна. За начало стартирайте Android Studio. Ако не го инсталирате, разгледайте пълното ни въведение в Android Studio, което надхвърля процеса на инсталиране. Сега стартирайте нов проект и не забравяйте да изберете шаблона „Празна активност“. Това е игра, така че, разбира се, не ви трябват елементи като бутона FAB, които усложняват нещата.


Първото нещо, което искате да направите, е да промените AppCompatActivity да се Дейност, Това означава, че няма да използваме функциите на лентата за действие.

По подобен начин ние също искаме да направим нашата игра на цял екран. Добавете следния код към onCreate () преди обаждането към setContentView ():

getWindow (). setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); this.requestWindowFeature (Window.FEATURE_NO_TITLE);

Обърнете внимание, че ако изпишете някакъв код и той се подчертае в червено, това вероятно означава, че трябва да импортирате клас. С други думи, трябва да кажете на Android Studio, че искате да използвате определени изявления и да ги направите достъпни. Ако просто щракнете където и да е върху подчертаната дума и натиснете Alt + Enter, тогава това ще бъде направено за вас автоматично!


Създаване на изглед на играта ви

Може да се използва за приложения, които използват XML скрипт за определяне на оформлението на изгледи като бутони, изображения и етикети. Това е линията setContentView прави за нас.

Но отново това е игра, което означава, че не е необходимо да имате прозорци на браузъра или да превъртате изгледи за рециклиране. Вместо това искаме вместо това да покажем платно. В Android Studio платно е точно такова, каквото е в изкуството: това е среда, върху която можем да рисуваме.

Затова променете този ред, за да се чете така:

setContentView (нов GameView (това))

Ще откриете, че това отново е подчертано червено. Но сега ако натиснете Alt + Enter, нямате възможност да импортирате класа. Вместо това имате възможност да създавам клас. С други думи, ние сме на път да направим собствен клас, който ще определи какво ще върви на платното. Това е, което ще ни позволи да привлечем към екрана, а не само да показваме готови изгледи.

Така че щракнете с десния бутон върху името на пакета във вашата йерархия отляво и изберете Ново> Клас, Сега ще ви бъде представен прозорец за създаване на класа ви и ще го наречете GameView, Под SuperClass напишете: android.view.SurfaceView което означава, че класът ще наследи методите - неговите възможности - от SurfaceView.

В полето (интерфейсите) ще пишете android.view.SurfaceHolder.Callback, Както при всеки клас, сега ние трябва да създадем нашия конструктор. Използвайте този код:

частна тема MainThread; обществен GameView (контекст на контекста) {super (контекст); . GetHolder () addCallback (това); }

Всеки път, когато класът ни бъде извикан да направи нов обект (в този случай нашата повърхност), той ще изпълни конструктора и той ще създаде нова повърхност. Редът „супер“ нарича суперклас и в нашия случай това е SurfaceView.

С добавянето на обратни обаждания ние сме в състояние да прихващаме събития.

Сега отменете някои методи:

@Override public void surfaceChanged (SurfaceHolder държател, int формат, int ширина, int височина) {} @Override public void surfaceCreate (SurfaceHolder притежател) {} @ Oververide public void surfaceDestroyed (SurfaceHolder притежател) {}

Те по принцип ни позволяват да отменим (оттук и името) методите в суперкласа (SurfaceView). Вече трябва да нямате повече червени подчертания в кода си. Ница.

Току-що създадохте нов клас и всеки път, когато се позоваваме на това, той ще изгражда платното за вашата игра, за да бъде нарисуван върху. класове създавам обекти и имаме нужда от още един.

Създаване на нишки

Новият ни клас ще бъде извикан MainThread, И нейната работа ще бъде да създаде конец. Нишката по същество е като паралелна вилица от код, която може да работи едновременно заедно с основен част от вашия код. Можете да имате много нишки, изпълняващи всички наведнъж, като по този начин позволявате на нещата да се случват едновременно, вместо да се придържате към строга последователност. Това е важно за играта, защото трябва да сме сигурни, че тя продължава да работи безпроблемно, дори когато се случва много.

Създайте своя нов клас точно както преди и този път той ще се разшири нишка, В конструктора ние просто ще се обадим супер (), Не забравяйте, че това е суперкласът, който е нишката и който може да направи цялото повдигане за нас. Това е като създаване на програма за миене на съдовете, които просто се обаждат пералня().

Когато се нарича този клас, той ще създаде отделна тема, която работи като издънка на основното. И е от тук че искаме да създадем нашия GameView. Това означава, че ние също трябва да се позоваваме на класа GameView и също така използваме SurfaceHolder, който съдържа платното. Така че, ако платното е повърхността, SurfaceHolder е станалът. И GameView е това, което го обединява.

Пълното нещо трябва да изглежда така:

обществен клас MainThread разширява нишката {private SurfaceHolder surfaceHolder; частен GameView gameView; обществен MainThread (SurfaceHolder surfaceHolder, GameView gameView) {super (); this.surfaceHolder = surfaceHolder; this.gameView = gameView; }}

Schweet. Вече имаме GameView и нишка!

Създаване на игровия цикъл

Сега имаме суровините, от които се нуждаем, за да направим нашата игра, но нищо не се случва. Това е мястото, където влиза цикълът за играта. По принцип това е цикъл от код, който се движи в кръг и се проверява входовете и променливите, преди да нарисувате екрана. Нашата цел е да направим това възможно най-последователно, така че да няма затормозяване или хълцане в кадъра, което ще проуча малко по-късно.

Засега все още сме в MainThread клас и ще заменим метод от суперкласа. Този е тичам.

И става малко нещо подобно:

@Override public void run () {докато (работи) {canvas = null; опитайте {canvas = this.surfaceHolder.lockCanvas (); синхронизиран (surfaceHolder) {this.gameView.update (); this.gameView.draw (платно); }} улов (изключение е) {} накрая {if (canvas! = null) {опитайте {surfaceHolder.unlockCanvasAndPost (canvas); } улов (изключение д) {e.printStackTrace (); }}}}}

Ще видите много подчертаване, така че трябва да добавим още няколко променливи и референции. Върнете се на върха и добавете:

частен SurfaceHolder surfaceHolder; частен GameView gameView; частно булево бягане; публично статично платно на платното;

Не забравяйте да импортирате Canvas. Платното е нещото, което всъщност ще рисуваме. Що се отнася до „lockCanvas“, това е важно, тъй като това по същество замразява платното, за да ни позволи да рисуваме върху него. Това е важно, защото в противен случай може да имате няколко нишки, които се опитват да нарисуват върху него наведнъж. Просто знайте, че за да редактирате платното, първо трябва да направите ключалка платното.

Актуализацията е метод, който ние ще създадем и тук ще се случат забавните неща.

Най- опитвам и улов междувременно са просто изисквания на Java, които показват, че сме готови да опитаме и да се справим с изключения (грешки), които могат да възникнат, ако платното не е готово и т.н.

И накрая, ние искаме да можем да стартираме нишката си, когато имаме нужда от нея. За целта тук ще ни е необходим друг метод, който ни позволява да настроим нещата. Това е, което тичане променливата е за (обърнете внимание, че Boolean е тип променлива, която е само някога вярна или невярна). Добавете този метод към MainThread клас:

public void setRunning (boolean isRunning) {running = isRunning; }

Но в този момент все още трябва да се подчертае едно нещо и това е актуализация, Това е така, защото все още не сме създали метода за актуализиране. Затова се върнете обратно GameView и сега добавете метод.

публична актуализация за невалидни () {}

Ние също трябва начало нишката! Ще направим това в нашето surfaceCreated метод:

@Override public void surfaceCreate (SurfaceHolder hold) {thread.setRunning (вярно); thread.start (); }

Ние също трябва да спрем конеца, когато повърхността е унищожена. Както може би се досещате, ние се справяме с това в surfaceDestroyed метод. Но тъй като всъщност може да отнеме няколко опита за спиране на нишка, ние ще поставим това в цикъл и използваме опитвам и улов отново. Така:

@Override public void surfaceDestroyed (държач на SurfaceHolder) {boolean retry = true; докато (опитайте отново) {опитайте {thread.setRunning (невярно); thread.join (); } улов (InterruptException e) {e.printStackTrace (); } повторен опит = невярно; }}

И накрая, насочете се към конструктора и не забравяйте да създадете новия екземпляр на вашата нишка, в противен случай ще получите страховитото изключение на нулевия указател! И тогава ще направим GameView фокусиран, което означава, че може да обработва събития.

тема = нов MainThread (getHolder (), това); setFocusable (истина);

Сега ти можеш накрая всъщност тествайте това нещо! Точно така, щракнете върху Изпълни и го Трябва всъщност работи без никакви грешки. Подгответе се да бъдете взривени!

Това е ... това е ... празен екран! Целият този код. За празен екран. Но това е празен екран на възможност, Имате своя повърхност и работи с цикъл за игра, за да обработвате събития. Всичко, което е останало, е да направим нещата. Дори няма значение дали не сте следвали всичко в урока до този момент. Важното е, че можете просто да рециклирате този код, за да започнете да правите славни игри!

Правете графика

Точно сега, ние имаме празен екран, който да рисуваме, всичко, което трябва да направим, е да рисуваме върху него. За щастие, това е простата част. Всичко, което трябва да направите, е да отмените метода на теглене в нашия GameView клас и след това добавете няколко хубави снимки:

@Override public void draw (Canvas canvas) {super.draw (платно); ако (canvas! = null) {canvas.drawColor (Color.WHITE); Боя за боя = нова Paint (); боя.setColor (Color.rgb (250, 0, 0)); canvas.drawRect (100, 100, 200, 200, боя); }}

Изпълнете това и сега трябва да имате доста червен квадрат в горната лява част на иначе бялия екран. Това със сигурност е подобрение.

Теоретично бихте могли да създадете почти цялата си игра, като я залепите вътре в този метод (и по-важното) onTouchEvent да се справите с приноса), но това не би било ужасно добър начин да вършите нещата. Поставянето на нова боя в нашия цикъл ще забави значително нещата и дори ако поставим това другаде, добавяйки твърде много код към рисувам метод ще стане грозен и трудно да се следва.

Вместо това има много по-голям смисъл да боравите с игровите обекти със собствените си класове. Ще започнем с един, който показва характер и този клас ще се нарича CharacterSprite, Върви напред и направи това.

Този клас ще нарисува спрайт върху платното и ще изглежда така

публичен клас CharacterSprite {личен Bitmap изображение; публичен характер характер (Bitmap bmp) {image = bmp; } публична невалидна рисунка (Canvas canvas) {canvas.drawBitmap (изображение, 100, 100, нула); }}

Сега, за да използвате това, ще трябва първо да заредите растерната карта и след това да извикате класа от GameView, Добавете препратка към частен характерSprite характерSprite и след това в surfaceCreated метод, добавете реда:

znakSprite = нов CharacterSprite (BitmapFactory.decodeResource (getResources (), R.dravable.avdgreen));

Както можете да видите, растерната карта, която зареждаме, се съхранява в ресурси и се нарича avdgreen (беше от предишна игра). Сега всичко, което трябва да направите, е да предадете тази растерна карта на новия клас в рисувам метод с:

characterSprite.draw (платно);

Сега щракнете върху стартиране и трябва да видите вашата графика да се появи на вашия екран! Това е BeeBoo. Аз го рисувах в учебниците си в училище.

Ами ако искахме да накараме този малък човек да се движи? Просто: ние просто създаваме x и y променливи за неговите позиции и след това променяме тези стойности в актуализация метод.

Затова добавете препратките към своите CharacterSprite и след това нарисувайте вашата растерна карта х, у, Създайте метода за актуализиране тук и засега просто ще опитаме:

Y ++;

Всеки път, когато цикълът на играта работи, ще преместваме героя надолу по екрана. Помня, ш координатите се измерват отгоре, така че 0 е горната част на екрана. Разбира се, че трябва да се обадим на актуализация метод в CharacterSprite от актуализация метод в GameView.

Натиснете отново възпроизвеждане и сега ще видите, че вашето изображение бавно се проследява по екрана. Все още не печелим награди за игра, но това е начало!

Добре, да направим нещата малко по-интересното е, просто ще пусна тук някакъв код на „подскачаща топка“. Това ще накара нашия графичен отскок около екрана от ръбовете, като тези стари скрийнсейвъри на Windows. Знаете ли, странно хипнотичните.

публична актуализация за невалидни () {x + = xVelocity; y + = ускорение; if ((x & gt; screenWidth - image.getWidth ()) || (x <0)) {xVelocity = xVelocity * -1; } if ((y & gt; screenHeight - image.getHeight ()) || (y <0)) {yVelocity = yVelocity * -1; }}

Вие също ще трябва да дефинирате тези променливи:

частен int xVelocity = 10; частен int yVelocity = 5; private int screenWidth = Resources.getSystem (). getDisplayMetrics (). widthPixels; private int screenHeight = Resources.getSystem (). getDisplayMetrics (). височинаPixels;

Оптимизация

Има много повече, за да се задълбочим тук, от обработката на входа на плейъра, до мащабирането на изображенията, до управлението на това, че много герои се движат по екрана наведнъж. В момента персонажът подскача, но ако погледнете много внимателно, има леко заекване. Не е ужасно, но фактът, че можете да го видите с просто око, е нещо като предупредителен знак. Скоростта също варира много в емулатора в сравнение с физическо устройство. А сега си представете какво се случва, когато имате т става на екрана наведнъж!

Има няколко решения на този проблем. Това, което искам да направя, е да създам частно цяло число MainThread и наречете това targetFPS, Това ще има стойността 60.Ще се опитам да накарам играта си да работи с тази скорост и междувременно ще проверя дали е така. За това искам и частен двойник, наречен averageFPS.

Също така ще актуализирам тичам метод, за да се измери колко време отнема всеки цикъл на играта и след това да пауза този цикъл на играта временно, ако изпревари targetFPS. След това ще изчислим колко дълго сега взе и след това отпечатайте, за да можем да го видим в дневника.

@Override public void run () {long startTime; дълго времеMillis; дълго чакане; дълго общо време = 0; int frameCount = 0; дълъг targetTime = 1000 / targetFPS; докато (работи) {startTime = System.nanoTime (); платно = нула; опитайте {canvas = this.surfaceHolder.lockCanvas (); синхронизиран (surfaceHolder) {this.gameView.update (); this.gameView.draw (платно); }} улов (изключение е) {} накрая {if (canvas! = null) {опитайте {surfaceHolder.unlockCanvasAndPost (canvas); } улов (изключение д) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; опитайте {this.sleep (waitTime); } улов (изключение д) {} totalTime + = System.nanoTime () - startTime; frameCount ++; ако (frameCount == targetFPS) {среднаFPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (averageFPS); }}}

Сега нашата игра се опитва да заключи FPS до 60 и трябва да откриете, че тя обикновено измерва доста стабилни 58-62 FPS на модерно устройство. На емулатора обаче може да получите различен резултат.

Опитайте да промените тези 60 на 30 и вижте какво ще се случи. Играта се забавя и то Трябва сега прочетете 30 във вашата логката.

Заключителни мисли

Има някои други неща, които можем да направим, за да оптимизираме и производителността. Тук има страхотна публикация в блога. Опитайте се да се въздържате от създаването на нови случаи на Paint или растерни карти в цикъла и направете всичко инициализиране извън преди началото на играта

Ако планирате да създадете следващата хитова Android игра, тогава има разбира се по-лесни и по-ефикасни начини за справяне с тези дни. Но определено все още има сценарии за използване на случаите, когато можете да рисувате върху платно и е много полезно умение да добавите към репертоара си. Надявам се това ръководство да е помогнало донякъде и да ви пожелая късмет в предстоящите ви начинания за кодиране!

СледващияРъководство за начинаещи за Java

ExpreVPN изисква имейл адрес за регистрация. Те гарантират, че тази информация няма да бъде споделена - тя се използва само за предоставяне на всичко, което може да ви е необходимо във връзка с обслуж...

F1 Manager следва в гумите следите на изявени игри на мениджърите на автомобилен спорт като ... Motorport Manager. Във всеки случай заглавието е по-рационално, съсредоточено върху свободата във формул...

Свежи Публикации