📜 ⬆️ ⬇️

[libGDX] Writing a full game for Android. Part 2

Hello! Less than a day since the publication of the first part of the article, but I can not sleep, as there is an unfinished business and you need to finish the article. Let's get started

I will make another reservation. I'm not a Java expert, and therefore the following code may confuse many, but I wrote the game in less than a week and worked more for the result than for the beauty and decency of the code. I hope in the comments there will be someone who will help to make the code and the structure of the project, if not perfect, then at least lead to a good view and allow me and the rest to become better programmers. Okay, enough of the lyrics, let's continue our “hardcore”.
Create a new package and name it objects . In it we will create a background class, and add the following code to it:

BackgroundActor.java file

package ru.habrahabr.songs_of_the_space.objects; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.scenes.scene2d.Actor; public class BackgroundActor extends Actor { private Texture backgroundTexture; private Sprite backgroundSprite; public BackgroundActor() { backgroundTexture = new Texture("images/sky.jpg"); backgroundSprite = new Sprite(backgroundTexture); backgroundSprite.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); } @Override public void draw(Batch batch, float alpha) { backgroundSprite.draw(batch); } } 

')
Nothing complicated. This is an “actor” that fits the size of the user's screen and makes our game more like a starry sky. It should look something like this:
The main screen of the game
image


Now we will add it to MyGame.java and make it accessible from the outside, in order not to create it on every next screen. It will save us from blinking.

MyGame.java file

  //   create() public BackgroundActor background; @Override public void create() { ... background = new BackgroundActor(); background.setPosition(0, 0); ... } 


Next, we have to add it to the scene in every new screen:

 stage.addActor(game.background); 


Now, also in the package of objects we will create a note class. He will keep all our notes in the sequence we need.

Note.java file

 package ru.habrahabr.songs_of_the_space.objects; public class Note { private String note; private float delay; private Star star; //  .     xml  . public void setNote(String note) { this.note = note; } public String getNote() { return this.note; } //    ,        public void setDelay(String delay) { this.delay = Float.parseFloat(delay); } public float getDelay() { return this.delay; } //   --  public void setStar(Star star) { this.star = star; } public Star getStar() { return this.star; } } 


Now that we have created the note, we need to create a star that will be our main actor in our space scene. She will flicker and sing her wonderful melody for future users.
Before continuing, I will explain a little why we need a separate class for the note and for the star. The melody can repeat its notes, and each star should be in a single copy. When I first thought up the idea of ​​the game, I just kept every note inside the star. As a result, either the melody was too simple, or there were too many stars in the sky and it was difficult to complete the level with even eight repetitive notes.
So, create a star.

Star.java file

 package ru.habrahabr.songs_of_the_space.objects; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Touchable; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; public class Star extends Actor { // ,    private Sound sound, wrong; //     private String note; //   private Sprite img; private Texture img_texture; //  .   ,     private Level level; public Star(String str_img, String str_sound) { img_texture = new Texture("images/stars/" + str_img + ".png"); img_texture.setFilter(TextureFilter.Linear, TextureFilter.Linear); img = new Sprite(img_texture); //     ,          img.setSize(Gdx.graphics.getHeight() * 15 / 100, Gdx.graphics.getHeight() * 15 / 100); this.note = str_sound; this.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/bells/" + str_sound + ".mp3")); this.wrong = Gdx.audio.newSound(Gdx.files.internal("sounds/bells/wrong.mp3")); //        ,            addListener(new ClickListener() { @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { img.setScale(1.2f); if (note.equals(level.getCurrentNoteStr())) { level.setCurrentNote(); Gdx.input.vibrate(25); //   ,         getSound().play(); } else { //   ,   .       .    ,     . level.setCurrentNote(0); level.setEndNote(true); level.setPlayMusic(); getWrongSound().play(); Gdx.input.vibrate(80); } return true; } @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { img.setScale(1.0f); //      ,     ,    } }); setTouchable(Touchable.enabled); //       } public void setLevel(Level level) { this.level = level; } //      ,        @Override public void setBounds(float x, float y, float width, float height) { super.setBounds(x, y, this.img.getWidth(), this.img.getHeight()); this.img.setPosition(x, y); } //    ,    .  . @Override public void act(float delta) { img.rotate(0.05f); } //     @Override public void draw(Batch batch, float alpha) { this.img.draw(batch); } public Sound getSound() { return this.sound; } public Sound getWrongSound() { return this.wrong; } public String getNote() { return this.note; } public Sprite getImg() { return this.img; } } 


Now create our class level. He will be responsible for creating all the actresses and actors, as well as playing the melody and congratulating on the victory. I added it to the package of objects , but it is better suited as a manager, so you can transfer it there yourself.

Level.java file

 package ru.habrahabr.songs_of_the_space.objects; import java.util.HashMap; import java.util.Map; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.scenes.scene2d.Touchable; import com.badlogic.gdx.utils.Array; public class Level { private XMLparse xml_parse; private Array<Note> notes = new Array<Note>(); private Array<Star> stars = new Array<Star>(); private Map<String, Array<String>> starsPos = new HashMap<String, Array<String>>(); private int currentNote; private int endNote; private float delay; private boolean playMusic; private boolean win; private final Sound winner = Gdx.audio.newSound(Gdx.files.internal("sounds/win.mp3")); //    public Level(String level) { xml_parse = new XMLparse(); Array<Star> xml_stars = xml_parse.XMLparseStars(); //       notes = xml_parse.XMLparseNotes(level); //     starsPos = xml_parse.getPos(level); //      endNote = 3; delay = 0; this.win = false; setPlayMusic(); for (Note n : this.notes) { for (Star s : xml_stars) { if (n.getNote().equals(s.getNote()) && !this.stars.contains(s, true)) { //    xml       ,     this.stars.add(s); } if (n.getNote().equals(s.getNote())) n.setStar(s); //          } } for (Star s : this.stars) { s.setLevel(this); s.setBounds( //    ,              (            ) Gdx.graphics.getWidth() * Float.parseFloat(starsPos.get(s.getNote()).get(0)) / 100, Gdx.graphics.getHeight() * Float.parseFloat(starsPos.get(s.getNote()).get(1)) / 100 - s.getImg().getHeight() / 2, s.getImg().getWidth(), s.getImg().getHeight() ); } } public boolean isWin() { return this.win; } //    public void setEndNote() { if (this.endNote < this.notes.size - 1) { this.endNote += 4; } } //    ,   ,   ,    . //      ,     . ! ! public void setEndNote(boolean begin) { if (begin) { this.endNote = 3; } } public void setCurrentNote(int note) { this.currentNote = note; } //    public void setCurrentNote() { if (this.currentNote < this.notes.size - 1) { this.currentNote++; if (currentNote - 1 == endNote) { currentNote = 0; setEndNote(); //    4    setPlayMusic(); //       } } else { //     ,    this.endNote = notes.size - 1; this.currentNote = 0; this.win = true; this.winner.play(); } } public int getCurrentNote() { return this.currentNote; } public String getCurrentNoteStr() { return this.notes.get(this.currentNote).getNote(); } public Array<Note> getNotes() { return this.notes; } public Array<Star> getStars() { return this.stars; } public void setPlayMusic() { if (playMusic) { playMusic = false; } else { playMusic = true; } } //      public void playStars() { if (playMusic) { for (Star s : stars) { s.setTouchable(Touchable.disabled); //      ,    } if (getCurrentNote() < notes.size) { if (getCurrentNote() <= endNote) { Note note = notes.get(getCurrentNote()); delay += note.getDelay(); // delay         if (delay >= 0.9f) note.getStar().getImg().setScale(1.2f); //        ,     if (delay >= 1.0f) { delay = 0; setCurrentNote(currentNote + 1); note.getStar().getSound().play(); note.getStar().getImg().setScale(1f); } } else { setPlayMusic(); setCurrentNote(0); } } else { delay = 0; setCurrentNote(0); setPlayMusic(); } } else { for (Star s : stars) { s.setTouchable(Touchable.enabled); //        } } } } 


I hope everything is clear. I tried to comment on the code as much as possible. The only thing that can cause questions is delay . I will explain a little. The playStars () method will be called in the render () method of the PlayScreen.java class. Since it is executed in the stream, every time all the conditions coincide, the delay will increase by the specified amount. Thus, the delay in the game of notes will be simulated. It is better to see in the code. Let's finally fill our PlayScreen.java class. Since there is a lot of code, I decided to hide it under the spoiler.

PlayScreen.java file
 package ru.habrahabr.songs_of_the_space.managers; import ru.habrahabr.songs_of_the_space.MyGame; import ru.habrahabr.songs_of_the_space.objects.GamePreferences; import ru.habrahabr.songs_of_the_space.objects.Level; import ru.habrahabr.songs_of_the_space.objects.PlayStage; import ru.habrahabr.songs_of_the_space.objects.PlayStage.OnHardKeyListener; import ru.habrahabr.songs_of_the_space.objects.Star; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Touchable; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.viewport.ScreenViewport; public class PlayScreen implements Screen { final MyGame game; private GamePreferences pref; private Level level; private String sL, nL; private Array<Star> stars; private PlayStage stage; private Table table, table2; public PlayScreen(final MyGame gam, String strLevel, String strNextLevel) { game = gam; this.sL = strLevel; this.nL = strNextLevel; stage = new PlayStage(new ScreenViewport()); stage.addActor(game.background); //   pref = new GamePreferences(); level = new Level(strLevel); stars = level.getStars(); level.setCurrentNote(0); for (final Star s : stars) { stage.addActor(s); //    ()   } LabelStyle labelStyle = new LabelStyle(); labelStyle.font = game.font; // Skin  ,       Skin skin = new Skin(); TextureAtlas buttonAtlas = new TextureAtlas(Gdx.files.internal("images/game/images.pack")); skin.addRegions(buttonAtlas); TextButtonStyle textButtonStyle = new TextButtonStyle(); textButtonStyle.font = game.font; textButtonStyle.up = skin.getDrawable("button-up"); textButtonStyle.down = skin.getDrawable("button-down"); textButtonStyle.checked = skin.getDrawable("button-up"); //      ,        table = new Table(); table.padTop(20); table.center().top(); table.setFillParent(true); // label     Label label = new Label(game.langStr.get("Constellation"), labelStyle); table.add(label); table.row().padBottom(30); label = new Label(game.langStr.get("level_" + strLevel), labelStyle); table.add(label); table.setVisible(false); stage.addActor(table); table2 = new Table(); table2.center().bottom(); table2.setFillParent(true); table2.row().colspan(2).padBottom(30); label = new Label(game.langStr.get("YouWin"), labelStyle); table2.add(label).bottom(); table2.row().padBottom(20); TextButton button = new TextButton(game.langStr.get("Again"), textButtonStyle); //         () //  ,  ,    button.addListener(new ClickListener() { @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { Gdx.input.vibrate(20); return true; }; @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { game.setScreen(new PlayScreen(game, sL, nL)); dispose(); }; }); table2.add(button); //          button = new TextButton(game.langStr.get("Levels"), textButtonStyle); button.addListener(new ClickListener() { @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { Gdx.input.vibrate(20); return true; }; @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { game.setScreen(new LevelScreen(game)); dispose(); }; }); table2.add(button); table2.setVisible(false); stage.addActor(table2); Gdx.input.setInputProcessor(stage); Gdx.input.setCatchBackKey(true); stage.setHardKeyListener(new OnHardKeyListener() { @Override public void onHardKey(int keyCode, int state) { if (keyCode == Keys.BACK && state == 1){ game.setScreen(new LevelScreen(game)); } } }); } @Override public void render(float delta) { //        Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); //      act()    ,      (  ,   ) stage.act(delta); stage.draw(); level.playStars(); //   ,      , label'   if (level.isWin()) { table.setVisible(true); table2.setVisible(true); pref.setLevel(nL); //    .  . for (Star s : stars) { s.setTouchable(Touchable.disabled); //          } } } @Override public void resize(int width, int height) {} @Override public void show() {} @Override public void hide() {} @Override public void pause() {} @Override public void resume() {} //        MyGame @Override public void dispose() { stage.dispose(); game.dispose(); } } 



Probably, the code has caused several questions, as you can see in it a new class GamePreferences.java . This class will allow us to store all game settings in a convenient format. For Android applications will be created, the so-called "SharedPreferences" . Read more here . In this case, in it we will store the levels passed by the user.
Well? Let's create and fill it now.

GamePreferences.java file

 package ru.habrahabr.songs_of_the_space.objects; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Preferences; public class GamePreferences { private Preferences pref; private static final String PREFS_NAME = "SONGS_OF_THE_SPACE"; private static final String PREF_LEVEL = "LEVEL_"; public GamePreferences() { pref = Gdx.app.getPreferences(PREFS_NAME); } public boolean getLevel(String level) { pref.putBoolean(PREF_LEVEL + 1, true); pref.flush(); return pref.getBoolean(PREF_LEVEL + level, false); } public void setLevel(String level) { pref.putBoolean(PREF_LEVEL + level, true); pref.flush(); } } 


There is nothing difficult in it. I will not duplicate the documentation, I gave a link to it below. Now we need to update our XMLparse.java class a little . So, we have not yet taught our parsit stars and notes. Let's do it.

XMLparse.java file
 package ru.habrahabr.songs_of_the_space.objects; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.badlogic.gdx.Application.ApplicationType; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.XmlReader; import com.badlogic.gdx.utils.XmlReader.Element; public class XMLparse { private Array<Star> stars = new Array<Star>(); private Array<Note> notes = new Array<Note>(); private Map<String, Array<String>> starsPos = new HashMap<String, Array<String>>(); //        .    ?    ! public HashMap<String, String> XMLparseLangs(String lang) { HashMap<String, String> langs = new HashMap<String, String>(); try { Element root = new XmlReader().parse(Gdx.files.internal("xml/langs.xml")); Array<Element> xml_langs = root.getChildrenByName("lang"); for (Element el : xml_langs) { if (el.getAttribute("key").equals(lang)) { Array<Element> xml_strings = el.getChildrenByName("string"); for (Element e : xml_strings) { langs.put(e.getAttribute("key"), e.getText()); } } else if (el.getAttribute("key").equals("en")) { Array<Element> xml_strings = el.getChildrenByName("string"); for (Element e : xml_strings) { langs.put(e.getAttribute("key"), e.getText()); } } } } catch (IOException e) { e.printStackTrace(); } return langs; } //      public Array<Star> XMLparseStars() { try { Element root = new XmlReader().parse(Gdx.files.internal("xml/stars.xml")); Array<Element> xml_stars = root.getChildrenByName("star"); for (Element el : xml_stars) { Star star = new Star( el.getAttribute("files"), el.getAttribute("files") ); stars.add(star); } } catch (IOException e) { e.printStackTrace(); } return this.stars; } //     public Array<String> XMLparseLevels() { Array<String> levels = new Array<String>(); Array<Integer> int_levels = new Array<Integer>(); FileHandle dirHandle; if (Gdx.app.getType() == ApplicationType.Android) { dirHandle = Gdx.files.internal("xml/levels"); } else { //  ,   libGDX -        Desktop  dirHandle = Gdx.files.internal(System.getProperty("user.dir") + "/assets/xml/levels"); } for (FileHandle entry : dirHandle.list()) { levels.add(entry.name().split(".xml")[0]); } for (int i = 0; i < levels.size; i++) { int_levels.add(Integer.parseInt(levels.get(i))); } int_levels.sort(); levels.clear(); for (int i = 0; i < int_levels.size; i++) { levels.add(String.valueOf(int_levels.get(i))); } return levels; } //   public Array<Note> XMLparseNotes(String strLevel) { try { Element root = new XmlReader().parse(Gdx.files.internal("xml/levels/" + strLevel + ".xml")).getChildByName("notes"); Array<Element> xml_notes = root.getChildrenByName("note"); for (Element el : xml_notes) { Note note = new Note(); note.setNote(el.getText()); note.setDelay(el.getAttribute("delay")); this.notes.add(note); } } catch (IOException e) { e.printStackTrace(); } return this.notes; } //    .  ,       ,        ,      public Map<String, Array<String>> getPos(String strLevel) { try { Element root = new XmlReader().parse(Gdx.files.internal("xml/levels/" + strLevel + ".xml")).getChildByName("positions"); Array<Element> xml_pos = root.getChildrenByName("position"); for (Element el : xml_pos) { Array<String> xy = new Array<String>(); xy.add(el.getAttribute("x")); xy.add(el.getAttribute("y")); this.starsPos.put(el.getAttribute("note"), xy); } } catch (IOException e) { e.printStackTrace(); } return this.starsPos; } } 



Left a little. True. Now, since I gave a hint about multilingual support, let's create a little I will explain how it will be. Based on the user's locale. For us, it starts with the symbol ru , for the English with en and so on. I translated the application into two languages, so the language file will be like this (and therefore in the code of the XMLparseLangs method there is a slightly strange condition):

Langs.xml file
 <?xml version="1.0"?> <langs> <lang key="en"> <string key="Play">Play</string> <string key="Exit">Exit</string> <string key="Again">Again</string> <string key="Levels">Levels</string> <string key="YouWin">You win!</string> <string key="Constellation">Constellation</string> <!-- Levels --> <string key="level_1">Canes Venatici</string> <string key="level_2">Triangulum</string> <string key="level_3">Equuleus</string> <string key="level_4">Apus</string> <string key="level_5">Sagitta</string> <string key="level_6">Musca</string> <string key="level_7">Ursa Minor</string> <string key="level_8">Orion</string> <string key="level_9">Ursa Major</string> <string key="level_10">Eridanus</string> <string key="level_11">Lacerta</string> </lang> <lang key="ru"> <string key="Play"></string> <string key="Exit"></string> <string key="Again"></string> <string key="Levels"></string> <string key="YouWin"> !</string> <string key="Constellation"></string> <!-- Levels --> <string key="level_1"> </string> <string key="level_2"></string> <string key="level_3"> </string> <string key="level_4"> </string> <string key="level_5"></string> <string key="level_6"></string> <string key="level_7"> </string> <string key="level_8"></string> <string key="level_9"> </string> <string key="level_10"></string> <string key="level_11"></string> </lang> </langs> 



As you can see, we take the attribute and use it to determine what to give to the user. Now we need to do something else. Create XML files of stars, notes, levels. Let's do it.

Stars.xml file
 <?xml version="1.0"?> <stars> <star files="c5" /> <star files="c#5" /> <star files="d5" /> <star files="d#5" /> <star files="e5" /> <star files="f5" /> <star files="f#5" /> <star files="g5" /> <star files="g#5" /> <star files="a5" /> <star files="a#5" /> <star files="b5" /> <star files="c6" /> <star files="c#6" /> <star files="d6" /> <star files="d#6" /> <star files="e6" /> <star files="f6" /> <star files="f#6" /> <star files="g6" /> <star files="g#6" /> <star files="a6" /> <star files="a#6" /> <star files="b6" /> </stars> 



If you glance through this file, you can see that it was a little goof when he said that there would be a star for each note. I made a different representation of the stars in different pitch. What for? To improve the sound, because if you take a more or less interesting constellation, then you can see, then it consists of at least 8-9 stars, but I didn’t really want to write a melody for 8-9 different notes, so I decided a little simplify your life by adding another octave.
Now give the file (for example) level.

1.xml file
 <?xml version="1.0"?> <level> <notes> <note delay="0.02f">d5</note> <note delay="0.05f">a6</note> <note delay="0.05f">d6</note> <note delay="0.05f">f#6</note> <note delay="0.02f">e5</note> <note delay="0.05f">a6</note> <note delay="0.05f">c#6</note> <note delay="0.05f">e6</note> <note delay="0.02f">d6</note> <note delay="0.05f">f#6</note> <note delay="0.05f">a6</note> <note delay="0.05f">d5</note> </notes> <positions> <position note="d5" x="5" y="35" /> <position note="a6" x="20" y="43" /> <position note="d6" x="40" y="50" /> <position note="f#6" x="55" y="45" /> <position note="e5" x="67" y="37" /> <position note="c#6" x="77" y="47" /> <position note="e6" x="90" y="50" /> </positions> </level> 



As you can see, we first determine the sequence of notes and their delay, and then we determine the position of each unique note in percentage terms. It seems that is all. If you forgot something, waiting for comments. Also, waiting for critics and advice. If anyone would be interested in the next article, I can describe the process of connecting AdMob to our game, tell how and where I took the sounds for the game, and also tell about how I laid out the game on Google Play. Thanks for attention!

Project files and an example of a finished game.

UPDATE. I decided not to write a new post, because I didn’t have enough material for the whole post, so I will leave here some corrections.

Bugs and fixes
For a start, the habrauser zig1375 wrote that it would be nice to use AssetManager. This is indeed a fair observation, because after selecting a level, the game seems to freeze for a while and as a result it is not entirely clear whether it is frozen or loaded. I solved this problem as follows. First, in the class MyGame.java, create an object of type AssetManager and make it public. , , LoaderScreen.java - :

LoaderScreen.java
 package ru.habrahabr.songs_of_the_space.managers; import ru.habrahabr.songs_of_the_space.MyGame; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.utils.viewport.ScreenViewport; public class LoaderScreen implements Screen { private MyGame game; private Stage stage; private Table table; private LabelStyle labelStyle; private Label label; public LoaderScreen(MyGame gam) { game = gam; //     game.manager.load("some/sounds", Sound.class); game.manager.load("some/textureatlas.pack", TextureAtlas.class); stage = new Stage(new ScreenViewport()); stage.addActor(game.background); game.getHandler().showAds(false); labelStyle = new LabelStyle(); labelStyle.font = game.levels; table = new Table(); table.setFillParent(true); label = new Label(game.langStr.get("Loading"), labelStyle); table.add(label); stage.addActor(table); } @Override public void render(float delta) { Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); stage.act(delta); stage.draw(); if (game.manager.update()) { game.setScreen(new MainMenuScreen(game)); dispose(); } } 



, MyGame.java MainMenuScreen.java . . , :

 game.manager.get("some/file.png", TextureAtlas.class); //  TextureAtlas     .           

, , , :

image


, - , , , .

Further. 1nt3g3r . , . , , . libGDX, . -, , 300 , . -, , , . ? . libGDX - :
 java -cp gdx.jar:extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker inputDir [outputDir] [packFileName] 


, region :
 starsAtlas = manager.get("images/stars/stars.pack", TextureAtlas.class); //    starsAtlas.findRegion("star1"), 


, sperson , libGDX json :
 Skin.get(String, Class<?>); 

, 1nt3g3r , xml, json. , , xml . json .

, AdMob. , , «» . . , 16 !

, Google Play. . , , , - , , . , , , Google Play. - , . , . , . .

, . FL Studio . , . Sytrus , , . , Audacity , - , , .
FreeSound . , , , .
, . ? . - , . , .

Source: https://habr.com/ru/post/224223/


All Articles