aboutsummaryrefslogtreecommitdiff
path: root/content/teaching/gameofcodes
diff options
context:
space:
mode:
Diffstat (limited to 'content/teaching/gameofcodes')
-rwxr-xr-xcontent/teaching/gameofcodes/01-goc-setup-basics.md296
-rw-r--r--content/teaching/gameofcodes/02-goc-input-movement.md270
-rw-r--r--content/teaching/gameofcodes/03-goc-input-rotation.md159
3 files changed, 725 insertions, 0 deletions
diff --git a/content/teaching/gameofcodes/01-goc-setup-basics.md b/content/teaching/gameofcodes/01-goc-setup-basics.md
new file mode 100755
index 0000000..d7c4fc7
--- /dev/null
+++ b/content/teaching/gameofcodes/01-goc-setup-basics.md
@@ -0,0 +1,296 @@
+Title: 01. (LibGDX) Game of Codes: The Setup & Basics
+Category: Game of Codes
+Tags: LibGDX, Tutorial, Game Dev
+Slug: 01-libgdx-game-of-codes-the-setup-basics
+Status: published
+
+**Hey everybody and welcome to a new/ old series on this blog about LibGDX.**
+
+LibGDX is a Java game development framework based on LWJGL and OpenGL which makes it relatively easy to make a game from scratch without requiring a big engine. It supports Desktop, Android, iOS and HTML as export targets which means that your game is automatically cross platform.
+
+Getting to know the framework can be challenging in the beginning, which is why I wanted to make a little series about it. Before I moved my blog to a static site generator I had a rather popular series about LibGDX called "Game of Codes". Unfortunately large parts of the guides are now outdated and no longer relevant. And the Wordpress export destroyed most of the formatting.
+
+Which is why I decided to rewrite them. Here it is: the Game of Codes! *plays theme song*
+
+NOTE: This tutorial requires a basic level of programming/ scripting skills. General Java knowledge is required or at the very least knowledge of how coding works. If you don't know that yet then I
+recommend [Bucky Roberts Java Programming series on Youtube](https://www.youtube.com/watch?v=Hl-zzrqQoSE&list=PLYJQBQw9Wdiid6eT1_DqBP3lnbJCzo3s8).
+It's very good!
+
+
+### Setting up LibGDX
+
+Now that we've got that out-of-the-way let's set up our workspace to make some neat games. I am writing and testing these tutorials on Linux. So if there are some platform specific issues you encounter, please give me feedback at [kookie@spacekookie.de](mailto:kookie@spacekookie.de).
+
+1. First of all you'll need to have Java and an IDE (Integrated Development Environment) installed on your computer. In this series I will be assuming that you're using **Eclipse**. For pointers on how to install that, please use Google!
+ - LibGDX uses Gradle as a build system. The latest version of eclipse has it integrated but older versions might require a plugin!
+3. Go to [libgdx.badlogicgames.com](http://libgdx.badlogicgames.com/) and download the libgdx setup app. It will help you configure your project with Gradle so you can either develop on it in a text editor of your choice or import it into an IDE.
+
+<img class="dual" src="/images/gameofcodes/series01/02_setup_ui.png" align="left">
+
+<img class="dual" src="/images/gameofcodes/series01/01_setup_ui.png" align="right">
+
+Let's step through the setup UI on your left real quick. We have some base settings. You can fill out the name of the game, the name of the main class as well as the package. If you're new to Java, the convention is that every application has a unique package root. And it's usually the reverse of a web-address. So for me it's `de.spacekookie` and then the project name. In homage to the original tutorial series I will call it `de.spacekookie.starchaser`.
+
+Also important to choose are the directory where to setup the project as well as your Android SDK location (if you want to build on Android). I will be ignoring Android for now and focus on the Desktop.
+
+<br/><br/><br/>
+
+<!-- Introduction to the module we need -->
+
+Make sure that you tick the following extentions (and extentions from the "third party" visible below the main window):
+
+ - Ashley (Entity management library)
+ - Box2D (2D physics)
+ - Box2DLights (2D realistic lighting)
+ - VisUI (Good looking skin for UI elements)
+
+Also make sure that if you want to use an IDE (such as Eclipse or IntelliJ) to select the project export from under "Advanced". When you're done with the configuration, hit that lovely "Generate" button and let's get going with development :)
+
+I will skip the importing step because that will be different for different IDE's. All I will say is that in Eclipse you should avoid putting your workspace *inside* your project directory as it will cause issues for you in the future (or during import).
+
+> **Tip**
+
+> While there are many ways to work on LibGDX, in this series I will assume that the project was added to Eclipse via Gradle while the building is done via a normal "Java Application" launch target in Eclipse. This is (in my opinion) the best of both worlds with a quick and easy build but the dependency management of Gradle built int the IDE.
+
+### Working with LibGDX
+
+So assuming that you were able to follow until here, you should now have a Java development IDE in front of you
+
+<!-- Add a picture of Eclipse here? -->
+
+> **Tip**
+
+> LibGDX is very closely entangled with Android. For example, if you create a project to have an Android target, all of the game assets will be stored in the "Android" subfolder because of who the system handles file imports. This means that the Desktop/ iOS and HTML versions only use symlinks to the Android assets directory.
+
+> If you don't have an Android project (only Desktop for example) assets are simply stored in your core project with all your game code!
+
+Now that everything is ready to go, let's investigate a little into what code was already generated for us and what we can do with it. Feel free to just hit that "build" button and get started but we're taking a more scientific approach :)
+
+<img class="dual" src="/images/gameofcodes/series01/04_eclipse.png" align="left">
+
+As you should already have noted there are several projects that were created for you. One project without a suffix and multiples with suffixes. The one project without a suffix is called the "meta" project (it contains relatively uninteresting things), while the other projects have to be divided into "core" and "targets". The idea is simple: you write all your logic, rendering and gameplay into the "core" while platform dependant code is used in the "targets". If this is complicated to understand, don't worry. It'll become clearer when using it.
+
+So as explained above, we will write most of our code in the highlighted "core" module. It is where you should in fact write all of your game code that isn't platform-specific to launch the game (for example getting the screen size or setting a custom icon).
+
+Please go ahead and open up the two files marked by arrows. They are the only code files that were generated for me. The lower one labelled `DesktopLauncher.java` contains the main function which will actually launch our game. The code should be very straight forward and we will look at the configuration settings later.
+
+<!-- Explain the basic structure of the project & function lifetimes -->
+
+The second file, labelled `StarChaser.java` in my case (and whatever you named your main class in the setup tool) contains much more interesting goodies: game code!
+
+Inspecting the code from the StarChaser class you can see a few functions in there that are responsible for describing the lifetime of our game object. These function are `create`, `render` and `dispose`. The create, play and, when we're done, destroy our game object. Everything else we do lives in between those functions.
+
+In fact, there are a few extra steps in between that are hidden from you by default. Check out the following list:
+
+```java
+
+/** Called when the game is created **/
+public void create();
+
+/** Called after create and every time the window is resized (if that is allowed) **/
+public void resize(int width, int heights);
+
+/** Starts calling after create() and resize() and will be
+ * recalled every frame. This is your game loop! **/
+public void render();
+
+/** Called when the game is closed on Android **/
+public void pause();
+
+/** Called when the game is re-opened on Android **/
+public void resume();
+
+/** Called when the game is closed. **/
+public void dispose();
+
+```
+
+This layout allows for very structured game code that walks through stages. You can of course allocate new objects in any of these functions to move functionality away from one class but in the end, you are always bound by the lifecycle of your game object. Note that all of these functions are provided by the `ApplicationAdapter` super-class that our main game class implements.
+
+> **Tip**
+
+> If you're ever curious about something you use/ extend/ implement works under the hood, don't be afraid to right-click on the part in question and click "Open Declaration" (when using Eclipse). This will open the source file for this module and you can see what is happening behind the scenes. In fact, I highly recommend being curious throughout this entire series.
+
+<!-- Explain the awefulness that is Eclipse run configurations -->
+
+If you haven't already launched the game to see what it does, I would recommend you do that now. Click the small black arrow next to the green "play" symbol in the top bar (or F5 in Eclipse), select "Launch Configurations" and create a new "Java Application" config. Check out the picture below for reference on how to fill it out. And if you have issues in this step, there are plenty of tutorials that go into depth online!
+
+![Eclipse Launch](/images/gameofcodes/series01/05_eclipse.png)
+
+
+<div class="alert alert-warning">
+<h1>Fixing an Eclipse error</h1>
+
+<br />
+
+<p>By default LibGDX uses Gradle. This means that paths are considered differently than when you're using Eclipse. For example, the above code will not by default work with Eclipse unless you tweak something. In fact, you might encounter an error like this:</p>
+
+<pre>
+Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load file: badlogic.jpg
+ at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:148)
+ at com.badlogic.gdx.graphics.TextureData$Factory.loadFromFile(TextureData.java:98)
+ at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:100)
+ at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:92)
+ at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:88)
+ at de.spacekookie.starchaser.StarChaser.create(StarChaser.java:17)
+ at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:147)
+ at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:124)
+Caused by: com.badlogic.gdx.utils.GdxRuntimeException: File not found: badlogic.jpg (Internal)
+ at com.badlogic.gdx.files.FileHandle.read(FileHandle.java:136)
+ at com.badlogic.gdx.files.FileHandle.readBytes(FileHandle.java:222)
+ at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:145)
+ ... 7 more
+</pre>
+
+<p>While when you build your project with <code>gradle run</code> it will work. This is because Eclipse handles import scopes differently and we need to respect that. You now have two choices:</p>
+
+<ol>
+ <li>You hard-code import paths from the filesystem root (i.e. "/home/spacekookie/.../artpack1/uss_pixel.png"</li>
+ <li>You add your assets folder to the source path in Eclipse. <strong>This is what I will be doing in this series!</strong></li>
+</ol>
+
+<p>Right-click on your desktop project and navigate to "configure build path" as shown in the picture below.</p>
+
+<img src="/images/gameofcodes/series01/06_eclipse.png">
+
+<p>Select "Add Folder" in the window that should have opened and in that dialog select "assets". Close the dialog and try to run the game again. It should now work!</p>
+
+<p>If you're having issues with this step, feel free to e-mail me at <a href="mailto:kookie@spacekookie.de">kookie@spacekookie.de</a></p>
+</div>
+
+### Understanding the Code
+
+*waits for you to launch the game*
+
+Cute, eh? Not exactly a game but it's a start. The example demonstrates a few basic principles as well as *super* basic 2D rendering. However, before we go, throw it all away and implement our own cool stuff we should try to understand how the current code works.
+
+
+```java
+//...
+
+public class StarChaser extends ApplicationAdapter {
+ SpriteBatch batch;
+ Texture img;
+
+ @Override
+ public void create () {
+ batch = new SpriteBatch();
+ img = new Texture("badlogic.jpg");
+ }
+
+ @Override
+ public void render () {
+ Gdx.gl.glClearColor(1, 0, 0, 1);
+ Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
+ batch.begin();
+ batch.draw(img, 0, 0);
+ batch.end();
+ }
+
+ @Override
+ public void dispose () {
+ batch.dispose();
+ img.dispose();
+ }
+}
+```
+
+Let's ignore the package definition and import statements and jump straight into the class declaration. We're creating a class, extending the `ApplicationAdapter` which is responsible for turning the class into an actual game object (as described above).
+
+The first function that would be invoked is the Constructor. Because there is none here, we will skip it. The next function being called is `create()`. It initialises a new SpriteBatch and afterwards a texture for "badlogic.jpg".
+
+You will be able to find the texture in the assets folder. And, if you change it, you will notice the changes in game as well. So far so good. What the hell is a SpriteBatch?
+
+A `SpriteBatch` is an object which is used to keep context during 2D render calls. Basically, you give it a positional and transformational reference frame (in our case DEFAULT) and then tell it to draw 2D images. But I'm getting ahead of myself. Because in this function we only create a new SpriteBatch. So all is good.
+
+Moving swiftly on to the `render()` function. This one is more interesting. The first two lines are two OpenGL calls which prepare a frame to be drawn. The first line sets up a colour while the second line tells the graphics processor to take the prepared colour and paint the entire frame with it. The colour representation is in RGBA (Red, Green, Blue, Alpha) with floating numbers between 0 and 1. So (1, 0, 0, 1) is red. *Try to change the colour and see the result!*
+
+The last three lines in the `render` function tell the SpriteBatch we created early to start, draw our texture and afterwards stop again. This marks the end of the frame at which point the next one will begin shortly.
+
+> **Tip**
+
+> Try to copy the `batch.draw(...)` command and change the coordinates from (0,0) to (200, 0). You will notice how a second instance of our texture is drawn at a different location. Cool, eh?
+
+The last function in the file is `dispose()`. It is only called when we close the game and usually only has other dispose calls in it. In our case, we make sure to properly dispose of the SpriteBatch and the Texture as both of them allocate memory on the graphics processor and we don't want to leak memory!
+
+
+### Adding to the game
+
+Phew! That was quite a lot to take in, I'm sure. And don't worry if you're a bit fuzzy on some of the details. We will go over some of these things again when we use it. Additionally there are a lot of great resources out on the internet for you to help you out.
+
+But before we wrap up this (way too long) article, I want to do something to make the game feel more like...well, a game. So go ahead and open the image processor of your choice (I will be using GIMP) and create a 128x128 pixel texture that one might consider a spaceship.
+
+<!-- ADD PICTURE OF USS PIXEL HERE -->
+
+You don't have to neccessarily make it 128x128 (I will) but the dimentions of the picture need to be a power of two (so 2, 4, 8,
+16, 32, 64, 128, 256, 512, 1024, 2048, 4096, ...). This has to do with how computers load textures (details later).
+
+What is that you say? You're too lazy? You don't have an image processing application? You managed to delete Paint from your computer? Kudos. Fine, you can use my graphics (contains the USS Pixel, a laser burst and a background image from the web).
+
+**Download [my artpack here](/downloads/gameofcodes/artpack1.zip).**
+
+I would suggest you create a new directory inside your games "assets" folder so that we don't get confused about what's what. So this is how your core/assets/ folder should look like now:
+
+<pre>
+❤ (idenna) ~/P/p/c/starchaser/core> tree assets/
+assets/
+├── artpack1
+│   ├── background.png
+│   ├── pixel_blast.png
+│   └── uss_pixel.png
+└── badlogic.jpg
+
+1 directory, 4 files
+</pre>
+
+First, why don't you go and change the line
+
+```java
+ img = new Texture("badlogic.jpg");9
+```
+
+to
+
+```java
+img = new Texture("artpack1/uss_pixel.png");
+```
+
+and marvel at the amazingness that is my art skills :)
+
+When launching the game now you will notice that the face texture has been replaced with a spaceship. However, this doesn't feel very space-y or even game-y yet. So let's not stop here! Reserve a new texture variable in your class and create it with a different resource file during the create function. Your source code should resemble something like the following
+
+```java
+Texture img, background;
+
+@Override
+public void create() {
+ batch = new SpriteBatch();
+ img = new Texture("artpack1/uss_pixel.png");
+ background = new Texture("artpack1/background.png");
+}
+```
+
+Then in the render function, before drawing the ship, draw the background texture first! This will make sure that the background is always behind the ship and not vice versa.
+
+```java
+ batch.begin();
+ batch.draw(background, 0, 0);
+ batch.draw(img, 0, 0);
+ batch.end();
+```
+
+Run the game and feel your jaw drop. It should look a lot nicer now. There is still no game logic or advanced rendering but we're getting there. Try to flip the draw calls around and see what happens to the ship.
+
+Also, you might have played around with the draw calls earlier and realised that `batch.draw(...)` in it's simplest form takes a texture and a coordinate. We will use more advanced draw calls later as this (for example) can't consider rotation.
+
+![StarChaser Mk1](/images/gameofcodes/series01/07_gamechange.png)
+
+<hr/>
+
+Wow! That ended up being longer than I expected :)
+
+In the next tutorial we will look at how to bring movement into the game. This consists of actually updating certain parts of the game as well as handling user input. See you then!
+
+Kate
+
+[[Next post about Input & Movement](/game-of-codes/02-input-and-movement/)] \ No newline at end of file
diff --git a/content/teaching/gameofcodes/02-goc-input-movement.md b/content/teaching/gameofcodes/02-goc-input-movement.md
new file mode 100644
index 0000000..58aaa2c
--- /dev/null
+++ b/content/teaching/gameofcodes/02-goc-input-movement.md
@@ -0,0 +1,270 @@
+Title: 02. (LibGDX) Game of Codes: Input & Movement
+Category: Game of Codes
+Tags: LibGDX, Tutorial, Game Dev
+Slug: 02-input-and-movement
+Status: published
+
+Welcome back to the Game of Codes, an introduction series to the LibGDX framework. In the last edition we learned how to set up LibGDX with a new Java project and draw simple pictures onto the screen. We used textures to import that image and then drew it via a SpriteBatch.
+
+Today we will look at basic input handling and how to make things move on screen. And though we won't be able to cover everything in this article we will explore the basic input stack that LibGDX has to offer and how to make things in your game move.
+
+Exciting! :)
+
+A little note: all the code that gets shown off here is available in a [Github repository](https://github.com/spacekookie/starchaser) for you to tinker with. After each tutorial I tag the commit so that it's obvious what got changed when!
+
+You can also use that repository to report issues or give feedback if you'd like. Otherwise, my email is always available!
+
+### Registering input
+
+Before we talk about inputs, we need to think about what it even means to register an input. When the user presses a button in our game, we want that button press to notify us so we can affect some behaviour. To understand what is going on here, we should consult the following graphic.
+
+![Life of a Frame](/images/gameofcodes/series02/01_framelife.png)
+
+You can see that LibGDX (obviously) considers the main run loop of our game...a loop :) In this series we only really care about the purple boxes. And in this article in particular, we are only considering the first purple box: "Input". What LibGDX does during this step is poll all input hardware for activity. It then writes this activity into a buffer and signals all registered input adapters to handle their input.
+
+So with that in mind, there are two ways of checking for input. The first is essentially polling the hardware again yourself during the "Render" step, while the other hooks into the "Input" step and is called asynchronously.
+
+Both ways of handling input are slightly unique. And we will start with the polling aproach first to demonstrate some basic functions.
+
+First, go into the main game class and add a position variable into the class body:
+
+```java
+
+import com.badlogic.gdx.math.Vector2;
+
+public class StarChaser extends ApplicationAdapter {
+ //...
+
+ Vector2 position;
+
+ // ...
+}
+```
+
+Furthermore, in the `create` block of the game, initialise the position to some value that is greater than `(0,0)` and not too big to be off window :)
+
+```java
+ position = new Vector2(250, 150);
+```
+
+If you're not too familar with Java, what this means is that we declare `position` to be a object variable which means that every function in an instance of this class can access it (Object-Oriented Programming). In the `create` function we then initialise it to have a value other than `null`.
+
+What that means now is that we can use the position variable (which has an `x` and a `y` component) in our draw calls to tell the picture where to go. The main advantage of this is that when we change the position variable (say...via a button press), the picture gets an updated position!
+
+```java
+ public void render() {
+ Gdx.gl.glClearColor(1, 0, 0, 1);
+ Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
+
+ updateInputs();
+
+ batch.begin();
+ batch.draw(background, 0, 0);
+ batch.draw(img, position.x, position.y);
+ batch.end();
+ }
+```
+
+So far so good...wait. Do you see that `updateInputs()` function call there? That wasn't there last time. In fact, it doesn't yet exist. But it should soon. Why don't you go and create a new function in the class somewhere with the signature `void updateInputs() { ... }`. We will fill it's body with some stuff soon.
+
+So fundamentally, we want to poll inputs and then when we have determined that an input is pressed we want to enact some functionality. The simplest form of polling buttons is with the `Gdx.input.isKeyPressed(key)` function where `key` is an integer variable that corresponds to a key-code. Don't worry, there are bindings that make it easier and you don't have to manually check for numbers ;)
+
+> **Tip**
+
+> Other input polling functions include `isButtonPressed(button)` for mouse buttons as well as `getX()`, `getY()` which give you the cursor position in your game window!
+
+
+So why don't you add the following lines of code to your `updateInputs` function and see where it gets us.
+
+```java
+ if (Gdx.input.isKeyPressed(Keys.W)) {
+ position.y++;
+ } else if (Gdx.input.isKeyPressed(Keys.S)) {
+ position.y--;
+ } else if (Gdx.input.isKeyPressed(Keys.A)) {
+ position.x--;
+ } else if (Gdx.input.isKeyPressed(Keys.D)) {
+ position.x++;
+ }
+```
+
+You can run this now and see what happens. When we press the keys in question the image on screen will move all over the place. Cool! But...it's not particularly pretty, is it?
+
+For one, we can only move in one direction simultaniously. But even if we split the X-Y axis into two different if-blocks, there is still the problem that `W` will always have precedence over `S` and `A` will have precedence over `D`. Which means that if we press all keys, we will *always* move top-left. And that's not particularly great :(
+
+> **Tip**
+
+> Also consider the following: when you move in one direction you apply 1 to the axis you're moving along. But if you move in two directions, you apply 1 in both x and y direction. Which means that (via trigonometry) you actually move **~1.41** in total. This means your game isn't consistent about rules.
+
+> It's clear that more logic is required to move!
+
+So how do we fix this? We can of course add more logic to our `updateInputs()` function but it will result in a lot of dirty hacks. And while game development is often about making dirty hacks that work, starting a project off some will quickly make your code-base unmaintainable.
+
+
+### Using Input Adapters
+
+The second method of getting input from the user I mentioned earlier is via an input adapter. It can be considered faster because we only do input polling once and it allows us to use input signals between different game components (gameplay, game HUD, etc.)
+
+So how do we use this awesome functionality? Well, it's simple. We need an InputAdapter. So first, create a new class via Eclipse. If you don't know how, consult the *suuuuper* helpful screenshot below :')
+
+![Life of a Frame](/images/gameofcodes/series02/02_createclass.png)
+
+Give it a useful name like `InputHandle` or `ShipInputHandle` or something. You can be quite specific in the naming because you very often have multiple input adapters for different aspects and parts of your game. So being specific in the naming just helps you out in the long run.
+
+Once you've done that you should be greeted with a very boring and empty class in your editor. So we need to add some basic code to get going. I took the liberty of doing that and will now show off what I did (and you'll finally get to see what name I chose...).
+
+```java
+
+import com.badlogic.gdx.InputAdapter;
+import com.badlogic.gdx.math.Vector2;
+
+public class ShipInputHandle extends InputAdapter {
+ Vector2 shipPosition;
+
+ public ShipInputHandle(Vector2 shipPosition) {
+ this.shipPosition = shipPosition;
+ }
+}
+
+```
+
+So, as you can see we have a class that extends `InputAdapter` as a subclass. With that comes free functionality we don't have to implement ourselves. Additionally I create a constructor that takes a vector and stores it as an instance variable (like before in the game class). Note that we're not copying the value here but rather storing a reference to the "original" variable in the game.
+
+> **Tip**
+
+> If you're coming from a language like C or C++ this can be quite confusing. What is a copy, what is a reference? In general: java always passes by reference (pointer) unless it is a primitive value. What is a primitive value? `int`, `float`, `double`, `boolean`, `byte`, `long` and all other lower-case types that become purple in the IDE (keywords).
+
+Next up, let's handle some inputs! The principle is similar to the polling: we check what input we are handling (because we only have generic functions - this will become obvious in a second), then invoke some behaviour. But as we have already seen before, we need to store some state. And that's why this is perfect: we have a new class where we can store the input state to check against. But at the same time, it's contained and doesn't clutter our main game class.
+
+Now...to solve the problem of moving in multiple directions at the same time, without letting one direction take precidence over another we can use a tri-state variable. In Java this can easily be done with an enum. Create a enum titled `TS` (or TriState if you feel verbose) in our `ShipInputHandle` class and create two values `x` and `y` that use it. The initial value should be `NEUTRAL`
+
+```java
+ enum TS { POS, NEG, NEUT };
+
+ TS x = TS.NEUT, y = TS.NEUT;
+```
+
+In the `keyDown(int keycode)` and `keyUp(int keycode)` functions we can then use a switch statement to flick the `x` and `y` variables in their favour. We *can* also perform a simple check if the `x`, `y` variables are already set to avoid another direction overwriting our current movement. But then again, maybe you consider this preferred behaviour. I chose to perform the check in the following code!
+
+```java
+public boolean keyDown(int keycode) {
+
+ switch (keycode) {
+ case Keys.W:
+ if (y == TS.NEUT)
+ y = TS.POS;
+ break;
+ case Keys.S:
+ if (y == TS.NEUT)
+ y = TS.NEG;
+ break;
+ case Keys.A:
+ if (x == TS.NEUT)
+ x = TS.NEG;
+ break;
+ case Keys.D:
+ if (x == TS.NEUT)
+ x = TS.POS;
+ break;
+ }
+
+ return true;
+}
+```
+
+Notice that `return true` at the end of that function? That's what you could call "Input Cascade". It is a concept that we will use extensively in later articles of this series. In short, it is the concept of letting an input signal cascade through different input adapters until it is ended. Returning true in this function signals the core input controller that we are ending the signal: it will not cascade to lower ranking controllers. This means that if you replace it with a `return false`, controllers down the stack will be able to pick up on the signal and use it.
+
+But again, this will become important in later tutorials. For now, let's just end the signal and get it over with. Next up, we can implement the `keyUp` function very simply by checking what axis our key-presses affect and then resetting that direction back to `NEUT` if it is applicable. Not a perfect solution but something that will definately work is implemented below.
+
+```java
+public boolean keyUp(int keycode) {
+ switch (keycode) {
+ case Keys.W:
+ if (y == TS.POS)
+ y = TS.NEUT;
+ break;
+
+ case Keys.S:
+ if (y == TS.NEG)
+ y = TS.NEUT;
+ break;
+
+ case Keys.A:
+ if (x == TS.NEG)
+ x = TS.NEUT;
+ break;
+
+ case Keys.D:
+ if (x == TS.POS)
+ x = TS.NEUT;
+ break;
+ }
+
+ return true;
+}
+```
+
+Now we're almost done. One thing is missing however! We keep a state depending on the inputs of our user. But we don't apply anything to the vector we stored based on that state. This is where we will need to build something slightly custom because the InputAdapter doesn't force you into any workflow.
+
+I recommend you create a new function `void update() { ... }` in the input class and make it public. We consider this function to be called every frame and apply values to the x and y components of the position vector, depending on the state of our inputs.
+
+The following code very quickly checks if we need to apply movement at all (is not NEUT) and then does a conditional application of 1 or -1 to each component.
+
+```java
+public void update() {
+ if(x != TS.NEUT) shipPosition.x += (x == TS.POS) ? 1 : -1;
+ if(y != TS.NEUT) shipPosition.y += (y == TS.POS) ? 1 : -1;
+}
+```
+
+Now we're done modifying the ShipInputHandle...for now :) Go back to the main game class. There are two more things to do before we can enjoy our new input handles. First, remove the old `handleInputs()` function. We don't need or want it anymore. Also make sure to remove it's function call from the `render()` function.
+
+Secondly, create a ShipInputHandle object and initialise it with our vector. Take the following code segment as reference.
+
+The last line in the `create()` function is key and not to be forgotten! It registers our custom input handler with the LibGDX input system and makes sure that our functions are *actually* being called :)
+
+```java
+
+public class StarChaser extends ApplicationAdapter {
+
+ // ...
+
+ ShipInputHandle input;
+
+ @Override
+ public void create() {
+ // ...
+
+ position = new Vector2(250, 150);
+ input = new ShipInputHandle(position);
+
+ Gdx.input.setInputProcessor(input);
+ }
+
+ @Override
+ public void render() {
+
+ // ...
+
+ input.update();
+
+ // ...
+ }
+
+ // ...
+}
+```
+
+And that's it! Run that code and you'll be able to move the image around in a much nicer fashion! Again, this is far from perfect. And you will notice that switching quickly from going-left to going-right can make the whole thing just stop on "Neutral". You can remove the additional check which I added. Realistically, you need a lot more state to mirror what the user is putting into your system if you want real-feedback and logical behaviour from your units. But this will do for now!
+
+And more importantly...it should have given you a glimpse at how to use the InputAdapters.
+
+<hr />
+
+And that's it for this article! Originally I wanted to talk a little bit about rotation. But I realised that I would have had to make a lot of assumptions about systems and not be able to go into too much depth without making the article *waaaayy* too long.
+
+So that'll be handled in the [next issue](https://media.giphy.com/media/z85AlA6CBKxEI/giphy.gif).
+
+Have a good day/ night,
+
+Kate
diff --git a/content/teaching/gameofcodes/03-goc-input-rotation.md b/content/teaching/gameofcodes/03-goc-input-rotation.md
new file mode 100644
index 0000000..fb93d33
--- /dev/null
+++ b/content/teaching/gameofcodes/03-goc-input-rotation.md
@@ -0,0 +1,159 @@
+Title: 03. (LibGDX) Game of Codes: Rotation & Advanced Movement
+Category: Game of Codes
+Tags: LibGDX, Tutorial, Game Dev
+Slug: 03-rotation-and-advmovements
+Status: published
+
+Welcome back to the Game of Codes, an introduction series to the LibGDX framework. In the öast edition we learned how to listen for user input, keep it's state for consistency and apply it to the world we are building. We did this by simply using a vector as a position for an image to align to.
+
+Today we will have a look at some more input but more importantly: rotation! And with that, also look at some more advanced movement concepts like momentum and some advice how to implement certain movement patterns.
+
+A little note: all the code that gets shown off here is available in a [Github repository](https://github.com/spacekookie/starchaser) for you to tinker with. After each tutorial I tag the commit so that it's obvious what got changed when!
+
+You can also use that repository to report issues or give feedback if you'd like. Otherwise, my email is always available!
+
+
+### Naïve approach
+
+So let's just take a naïve approach here. We have a vector that is essentially the position of our "ship". And it can have a rotation. So what we do is listen for two new key presses (in my case for `Q` and `E` - left and right rotation) and then create another tri-state variable `rotation` that we can use to determine whether we should rotate left or right.
+
+```java
+ switch (keycode) {
+ case Keys.W:
+ // ...
+
+ /** Handling rotation */
+ case Keys.Q:
+ rotation = TS.NEG;
+ break;
+ case Keys.E:
+ rotation = TS.POS;
+ break;
+ }
+```
+
+The inverse applies for the `keyUp(...)` function.
+
+```java
+ switch (keycode) {
+ // ...
+
+ case Keys.Q:
+ if (rotation == TS.NEG)
+ rotation = TS.NEUT;
+ break;
+
+ case Keys.E:
+ if (rotation == TS.POS)
+ rotation = TS.NEUT;
+ break;
+ }
+```
+
+Our update code needs to be appended slightly. This isn't the most pretty way to do this but for now it'll be alright.
+
+```java
+public void update() {
+ // ...
+
+ if (rotation == TS.POS)
+ shipPosition.rotate(1);
+ else if (rotation == TS.NEG)
+ shipPosition.rotate(-1);
+}
+```
+
+Now. What does this actually mean. We rotate the *positional* vector for the ship. You might have an inkling of what is about to happen but if you don't start the game and look at it. Not quite what we had in mind, is it?
+
+![Bad rotation GIF](/images/gameofcodes/series03/01_badrotation.gif)
+
+So what's happening here? Well, our positional vector points to where the ship is. From the origin. Which is in the bottom left of the screen. At coordinates `(0, 0)`... So when we rotate the positional vector, we rotate the ship around the origin. Furthermore, we never told the `SpriteBatch` to rotate the image we're drawing. That's why the ship orientation stays exactly the same: pointed upwards.
+
+
+### Using TextureRegions
+
+So let's fix this one problem at a time. Let's actually make the ship texture rotate depending on some value (in our case, the phony vector angle). For this we need to look at how we draw things. Right now, that's a texture.
+
+A texture is essentially a raw memory map of an image, loaded onto the GPU. That's why the texture needs to be a power of two because that's how GPU's handle textures in their memory. But what this also means is that if we have multiple textures this will cause a lot of overhead because loading textures in and out of memory from the GPU is expensive.
+
+Also, all transformations to the texture we need to apply manually. Transformations include scaling, moving and rotation. And especially the last one can be challenging.
+
+**Enter: TextureRegion!**
+
+Now, a `TextureRegion` is a collection of textures, essentially a large texture with bits cut out of it. This way we can bundle all our textures together into one large one (or several large ones) while marking different parts of the texture as regions so that we can handle them in the future.
+
+What this also means is that simple transformations can be done on the CPU which is slower but much easier than performing them on the GPU. This means the textures are still stored on the GPU but we get more control over how to transform them. Let's use this in our game!
+
+```java
+
+public class StarChaser extends ApplicationAdapter {
+
+ // ...
+
+ TextureRegion img;
+
+ // ...
+
+ @Override
+ public void create() {
+ batch = new SpriteBatch();
+ img = new TextureRegion(new Texture("artpack1/uss_pixel.png"));
+
+ // ...
+ }
+```
+
+The code above creates a TextureRegion instead of a Texture. In this case, we aren't using any of the memory saving benefits of using TextureRegions but that doesn't matter. We can still take advantage of it.
+
+Specifically, we will change the `batch.draw(...)` function to take more parameters. But first, create a second vector, call it "direction" and initialise it with `(0, 1)`.
+
+```java
+
+final float sizeX = img.getRegionWidth();
+final float sizeY = img.getRegionHeight();
+
+batch.draw(img, // The TextureRegion we draw
+ position.x, // Root X position
+ position.y, // Root Y position
+ sizeX / 2, // Rotation origin X (center point)
+ sizeY / 2, // Rotation origin X (center point)
+ sizeX, // Draw width
+ sizeY, // Draw height
+ 1, 1, // Scaling factor (1 is fine)
+ direction.angle()); // Region angle (around origin)
+
+```
+
+Additionally, we need to adjust our ShipInputHandle class because we need to make it use our direction vector. The code snippet below will outline what you need to change. Essentially: we rotate our direction vector and noramlise it after every step because rotating vectors actually changes their length.
+
+```java
+public class ShipInputHandle extends InputAdapter {
+ Vector2 pos, dir;
+
+ // ...
+
+ public ShipInputHandle(Vector2 shipPosition, Vector2 direction) {
+ this.pos = shipPosition;
+ this.dir = direction;
+ }
+
+ // ...
+
+ public void update() {
+ if (rotation == TS.POS)
+ dir.rotate(1);
+ else if (rotation == TS.NEG)
+ dir.rotate(-1);
+
+ dir.nor();
+
+ // ...
+ }
+}
+```
+
+If you launch this configuration you will notice that the ship rotates around it's centre point correctly! YAY! You will notice that you can still move your ship independant of it's rotation. You might consider this a feature because it allows you to fly one way and shoot backwards (think Battlestar Galactica Vipers!). But in our case, we want the ship to always fly in the direction that it's pointing towards.
+
+![Proper rotation](/images/gameofcodes/series03/02_rotating.gif)
+
+This is relatively simple. We only need to change the position update code to make this happen. In fact, we only need to consider the direction vector when applying a new position. \ No newline at end of file