FinalProjectCheckpoints0-1
FinalProjectCheckpoints0-1
Project Description
We are finally tackling our final project! Before we get to rolling up our sleeves however, there are a couple things you should know
before getting started.
Project Philosophy
Throughout this project, we will be creating many common pieces of program functionality by hand. This is NOT because this
functionality doesn’t already exist somewhere in Java or inside our library. We’ve chosen a relatively simple application to build
(image editor) specifically to make a mountain out of a molehill. What this means is that many aspects of this project are going to be
blown up intentionally to be a little more difficult than they would normally be.
Why?
Typically, the content taught by this course is not commonly applied in most junior and mid-level software engineering positions out
in the real world. For the tasks you’ll be asked to solve at these levels, only a basic understanding of memory hierarchy and system
performance is required. Any program or code where it would be “valid” to use the approaches taught in this course directly instead
of using a pre-built solution would typically be inordinately complicated, and likely outside the reach of you and most of your peers.
We ARE making this particular program more difficult than it absolutely needs to be.
We are NOT building anything close to the difficulty of a real-world example
Last Note:
The approaches we will be taking in this program were not always selected because they are the cleanest, neatest, or best performing ways
of solving the problems will be encountering. The purpose of this program is to explore a variety of programming topics and problem-solving
methodologies. It is not necessarily recommended that you make use of these methods in a real-world software engineering environment.
That said, a concerted attempt was made to explain how to build good software. Within this project should be a number of illuminating
sections on Object Oriented design, program structure, language deficiencies, packages/namespaces, UI design and programming, and
more.
Generally speaking, it’s okay not to pull your hair out over the technical details of WHAT we are doing
Instead, shift your effort more towards understanding the WHY of what we’re doing instead
Checkpoints
0. Checkpoint 0
1. Checkpoint 0.5
2. Checkpoint 1
Checkpoint 0
Checkpoint Objectives:
• Find a partner
• Download LibGDX configuration tool
• Download Github Desktop (Or use cli if you’re already proficient in Git)
• Generate a new respository
• Generate a new project inside the repository with the LibGDX tool
• Add a screenshot of your program running, and the console printing out the names of you and your partner
• Push the project to your Git repo
NOTE: This entire checkpoint is going to be about setting up your project. This takes a non-trivial amount of time. It is HIGHLY
recommended that you start this checkpoint as early as possible, in case you run into issues getting the project configured.
For many of you, this might be your first larger project. Building larger software can be much more complicated than the smaller
programs you might be used to working on for school projects. Switching between machines as needed becomes a hassle,
overcomplicated/poorly written code will become difficult to remove after wiring it into your codebase, collaboration will become
difficult between everyone working on the project together.
To fix these issues, and hopefully make your experience with the project a little less painful, we will take advantage of the version
control software Git.
What is Git?
Git is a piece of software that allows us to save the current state of our codebase and upload it to a repository. This repos itory keeps a full
history of changes made to the codebase, and can also be split into multiple branches. These branches make it ea sy for multiple people to
work independently on the same project at the same time, and can be combined (or merged) to bring everyone’s changes together
Git is traditionally used through the command line, where we can type in commands to control our repository. While this is the
traditional and most foundational way of working with Git, it can be a little intimidating to people seeing it for the first time.
So for this project, instead of using Git the traditional way, the instructions in this manual will be written to utilize Github Desktop
instead as it offers the same functionality, but utilizes a full GUI to make things easier to get into.
To get started, you’ll need a Github account. You can create one on the official Github website.
https://github.com/
Make sure you have the base software of Git installed on your machine as well.
https://git-scm.com/downloads
And finally, after you’ve done that, go ahead and download Github Desktop and run it.
https://desktop.github.com/
Once you finally have everything working, our first step is going to be to create a new repository on our machine. You can do this by
pressing Ctrl + N, or going to File -> New Repository
Call your repository Image Editor, set the Git ignore to Java, and set the local path to wherever you want your project to be stored on
your machine.
Local Path is the directory your repository is going to be located inside of. Set it wherever you want
Click Create repository, and you should find a new folder created in your Local path called Image-Editor. If you open it, you should see
two files called .gitattributes and .gitignore. This will mean that you have successfully created your repository!
We will come back around to Github again once we finish off this section by generating our project. If you can see the above image in
your file explorer, you should be good to move on.
Ideally, we’re going to want to rely upon the compromise of using a pre-built library that is going to do a lot of the heavy lifting for us.
When it comes to Java graphics libraries, there are many. While I won’t be able to cover all of them, here are a couple.
• Java Abstract Window Toolkit (AWT)
o Released 1995
o The base graphics package of Java
o Only suited for minimal/simple/legacy GUI development
• Java Swing
o Released 1998
o Built off of AWT
o Provides a more feature rich experience compared to AWT. Built off a component based system (Buttons, fields, boxes,
etc) Is generally considered deprecated by its predecessor
• JavaFX
o Released 2008
o Built as a more modern replacement for Swing
o Still largely seen as the modern standard for Java GUI programming today
▪ Has been discontinued by Oracle however
▪ Modern JavaFX is no longer a part of the standard Java installation
▪ Not terribly popular for consumer applications due to constraints that lead to an outdated looking style
▪ Most commonly seen in B2B (business to business) applications
All of the above-mentioned graphics libraries are AWESOME … but, we’re not going to be using any of them for this project, for the
following reasons.
• Heavy automation
o They are very easy to use…
o All of the above libraries however, hide levels of functionality that pertain to the material of this course
• Deprecated
o The above libraries are all largely considered deprecated, for a variety of reasons
▪ They ARE still used in lots of commercial software
▪ But this has a high likelihood of changing in the future
• Abstracted
o These libraries all make GUI programming incredibly EASY
▪ But this is only achieved by displacing the programmer very far away from what their code is actually doing
o A (flawed?) premise
▪ Even if we only ever perform GUI programming at this abstracted layer professionally
▪ Knowing what our code is doing underneath the hood will empower us to take firmer control over our code, and
make it do much more interesting and rigorous activities
• This is a bit more of a personal opinion though, so it’s left here at the bottom
Because of the above reasons, we will be using a moderately lower-level graphics API for our final project, LibGDX.
What is LibGDX?
LibGDX is an open-source game development framework, built off of the Java graphics library LWJGL (Light Weight Java Game Library),
a Java based wrapper for OpenGL. LibGDX contains a large number of classes and methods that will help get us started in building a
moderately (for as far as this class is concerned) low-level application
I thought you said we were removing abstraction? What’s with the word soup?
We are removing SOME abstraction. Pure graphics code would be well beyond the scope of a 2000 level course
If you follow the link above, the first step in the official guide will be to download the LibGDX setup tool. Open it and configure it as
shown below.
Set your Output folder to the directory you created for your Github Repository
Once you’ve done this, click Generate, and your project will be created for you. You can verify this by checking Github Desktop. On the
left-hand side, you should see a list of new folders and files has shown up, with a Green “+” next to each of them, marking them as
having been added to the local repository.
Now that we have successfully generated our project, we are going to import it into our IDE, so we can actually work with it.
NOTE: For the duration of this project, it will be assumed that you are running the project in Eclipse. It is highly recommended th at you do
so as well, but you can complete this project in any IDE of your choice
To do this, open up Eclipse and in the top left, go to File -> Import. LibGDX uses Gradle to manage our project, so we’re going to go to
Grade -> Existing Gradle Project, and click next.
What is Gradle?
Gradle is a build tool. It automates and manages various parts of the development process. For our purposes, it isn’t actually terri bly
important what Gradle does as we won’t be interfacing with any of its major features. Just trust that it’s doing nice things for us under the
hood.
Now, when prompted, set the Project Root Directory to wherever your Image-Editor folder is located, and click Finish. Your auto-
generated codebase should now import into Eclipse.
The first thing you might notice is that our code doesn’t import as one, but actually three separate projects. The way LibGDX projects
are built, each platform we want our program to work on will be added as its own project. This is done because the same program will
have a lot of differences between its desktop version and mobile version. For our purposes, the vast majority of work that we are going
to do will be in the ImageEditor-core project.
To test and make sure that your project is actually working, open up the desktop project and try to run DesktopLauncher.java and it will
open up the default project screen.
If you can get this screen to show up, then your project is properly configured! Now we just have a little bit of wrapping up to do, and
we should be good.
0.2 Pushing our changes
Before we push all of our code out to our repository on Github, add this print statement to your main method, and put the names of
yourself and (if applicable) your partner, then take a screenshot of the default project running, and both of your names printing out in
the console.
Once this is done, head back to Github Desktop. We’re going to push all of the changes we’ve made to our online repository. The first
thing that we are going to do is fill out a Summary and description of what we’ve done.
Once you’ve done this, click “commit to main”, then go up to the top-right and click “Publish repository”. It will bring up a dialogue box.
Leave the setting as default and click “Publish repository” inside this dialogue box. Don’t worry too much just now what we did. We’ll
come back and explain the process again later.
If you did this correctly, you should be able to hop onto a web browser and log in to your Github account, and see your repository has
now been uploaded to the website.
If you ever want to download your project on a new machine, open Github Desktop and go to File -> Clone Repository. You can then
select your Image-Editor and clone the most recent version of the project onto your computer. Doing it this way is not only pretty nifty
and convenient, but also downloads all of the files needed for Git to track file-changes.
Those new to Github are likely to discover the “Download ZIP” button and be tempted to use that instead.
Those new to Github are also likely to discover the “Add file” button. This might be tempting to use as it allows users to upload files
directly to their Github repository directly, without having to interface with the underlying software of Git.
If you can see all of your files inside your Github repository, take a screenshot of the repository as well (like the one I showed above).
Go to Canvas and submit the picture of your project running, and the picture of your github repository as well.
Checkpoint 0.5
Our first look at our codebase is going to be intimidating at first. Take a breath and go slowly. By the end, we’re going to understand this
project is gonna feel just like home.
Note: This project is going to be dramatically more complicated than anything we have discussed before. As such, there are times that
the instructions in this manual are going to occasionally handwave certain pieces of functionality. Do not be afraid when this happens.
If an explanation leaves you confused or wanting, please check the LibGDX documentation. Otherwise, try not to sweat the minor
details. If a piece of functionality is ever handwaved, it is generally done so because it will either be unimportant or not worth going
into further detail upon.
https://libgdx.com/wiki/
Like with every program, we’ll start by looking at the main method to see if we can get an understanding of the life-cycle of our
program.
public static void main (String[] arg) {
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setForegroundFPS(60);
config.setTitle("ImageEditor");
System.out.println("Project made by: ______ and _____" );
new Lwjgl3Application(new ImageEditor(), config);
}
Reminder – Main is located inside Image Editor-desktop -> DesktopLauncher.java
As mentioned earlier in Objective 0 LibGDX is built off the back of another graphics library known as lightwight java graphics library. The
code here just sets up the broader context of our program and deals with the LWJGL side of things. We’re not going to touch much
here, but there are a couple lines of interest worth mentioning.
config.setForegroundFPS(60);
Controls the framerate of our application (How many times per second we attempt to update the contents of the screen)
config.setTitle("ImageEditor");
Sets the name of our application window. We can see the following effect by editing the String in the method call
And finally, we can see that our main method is ended with the following method call
Perplexingly, our main method hasn’t really revealed very much about our program at all. This is because the bulk of our program is
actually stored in ImageEditor-core. Let’s take a look and open ImageEditor.java.
Now this code may still be a mystery to us at the moment, but does look a bit less intimidating hopefully. Our default program exists in
three parts, and that’s how we’ll attempt to break it down.
Entry Point:
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
}
create() can be considered as the entry -point for the core part of our project
In our default program, we’re creating something called a SpriteBatch, which we’ll discuss in a moment. We can also see that we’re
loading in a jpeg image from somewhere. Oddly, we’re not giving a direct file-path, so where is this image located? We can find it
under Image-Editor -> assets.
All files that we want our project to use will be placed in our assets folder
We can actually experiment a little here by putting an image in our assets folder and trying to load that image instead, and running our
program.
By default, LibGDX is capable of handling most image file -types. Try setting this up with some image on your own computer, and running
the program.
This image is stored as a Texture. We don’t know a lot about it, but for now, it is safe to assume for now that a Texture is something
that allows to show data to the screen. Let’s try taking a look at our next method.
Update method:
public void render () {
ScreenUtils.clear(1, 0, 0, 1);
batch.begin();
batch.draw(img, 0, 0);
batch.end();
}
render() is called every time our program wants to refresh the contents of the screen
Right now, you are probably reading this manual on a computer. Go ahead and wiggle your mouse. What happens when you do this?
Well, obviously, the mouse on your screen moves in the same direction as your arm. Intuitive right? But how did this happen? This
behavior is probably so intuitive and ingrained in your muscle memory, that you might not have ever thought about this before.
Somewhere, perhaps buried deep inside our operating system’s codebase, there lies some code that possibly looks something like this.
class Mouse{
public int XPosition, YPosition;
}
Feel free to imagine what other code might exist in this theoretical class as well
Ah, that makes a bit of sense. If our mouse has an x and y position, then all we have to do is somehow detect when the mouse has
been moved. We can then do something like the following
Now all we have to do is show our mouse moving across the screen. But…how do we show movement?
I’ll reveal the trick here a little early and ruin the surprise a bit. We DON’T! Our computer is actually incapable of showing anything
move. Instead of moving, it’s more accurate to say that things like our mouse cursor teleport. Our display refreshes on a set interval.
Whenever this happens, everything currently on the screen disappears. Then, we go back and re-draw in everything. If the user moved
the mouse in this short time-interval, the mouse will now be drawn to a different part of the screen. If we refresh our screen often
enough, it will “look” like our mouse is actually moving when it’s not!
Our screen clears, our background is redrawn, and our mouse is drawn in a new position
Note: This is a simplification of this process, not all graphics libraries draw in items starting from the back to the front like this
This is what our render() method is doing. Remember back in DesktopLauncher, how there was a line of code that determined how
often the program would “refresh” itself?
config.setForegroundFPS(60);
This one!
Well, by default, this line tells our program to “refresh” 60 times per second. And every time we want to “refresh”, our program calls
render()
Our method starts by clearing the entire screen, and flooding it with a single color.
ScreenUtils.clear(1, 0, 0, 1);
This sets the full contents of the screen to black
Now obviously, I just told you what this code does, but how could we determine this for ourselves? Well, a couple ways actually. The
first and simplest, is to just mouse over the method-name itself. This will bring out a pop-up that gives us some information about
what this method does.
And perhaps the most fun way of testing this is to comment out all of the lines below and run our program again.
public void render () {
ScreenUtils.clear(1, 0, 0, 1);
// batch.begin();
// batch.draw(img, 0, 0);
// batch.end();
}
But lets also try messing with our method-call as well. The screenshot above says that the first three numbers represent how much
red, blue, or green we are going to flood the background with. Try setting each of these three numbers to any number you want
between 0 and 1.
Flooding the program with purple by setting the background color to nearly equal parts red and blue
To handwave a little, our SpriteBatch “batch” is responsible for drawing everything else to the screen.
batch.begin();
batch.draw(img, 0, 0);
batch.end();
We need to tell our SpriteBatch to begin a new batch whenever we want to draw something, and to end a batch when we’re done.
-If this sounds confusing, don’t worry, we’ll be playing with this later
Checkpoint 1
Checklist:
• Draw a Texture to the screen
• Draw a rectangle to the screen manually
• Create Rec2D class
• Switch renderer to use Rec2Ds
• Add Velocity to Rec2D
• Make Rec2D bounce off the side of the screen
• Make Rec2D change to a random color when it bounces
https://www.youtube.com/watch?v=5mGuCdlCcNM
Bouncing DVD Logo
By recreating this simple simulation, we’ll engineer the core structure around which our entire future program will revolve. This is all
going to begin with our first custom class (of many yet to come)
If we run our code though, we’ll see something a little disappointing. Our new Texture doesn’t seem to be showing up at all. This isn’t
because something is wrong with our program. It looks like we’re only drawing a single Texture because both img and secondImg are
being drawn to the exact same location on screen.
Overlapping textures
Luckily, there’s a pretty easy way to move our second Texture so it’s not overlapping our first anymore. Batch.draw() takes in arguments
that correspond to an X and Y coordinate. If we edit our code, we can make our program able to show both Textures at the same time.
Image drawn at (0,0) and (350, 0). All items are drawn with their position representing the bottom -left of the image.
Because we’re just drawing the same image twice, we don’t actually even need two textures in this case. We can delete secondImg
entirely, and our code will do the same thing.
SpriteBatch batch;
Texture img;
Texture secondImg;
@Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
secondImg = new Texture("badlogic.jpg");
}
@Override
public void render () {
ScreenUtils.clear(.4f, 0f, 0.5f, 1);
batch.begin();
batch.draw(img, 0, 0);
batch.draw(secondImg, 350, 0);
batch.draw(img, 350, 0);
batch.end();
}
Lines highlighted in RED are lines that should be deleted from our program
1.2 Rectangles
In computer graphics, shapes are the fundamental building blocks of everything that we create - Triangles, squares, circles, oblongs,
etc. By combining basic geographic shapes together, we can recreate any kind graphics our imagination desires.
But if we want to draw whatever our imagination desires, we’re going to have to write a LOT of code
So instead, for our program, we’re going to create a special limitation to reign in the scope of our project. EVERYTHING that we draw to
the screen is going to be a rectangle. That means every button, menu, and item in our application is going to be some kind of
rectangle. As we build out this project, we’ll see that this limitation is going to make our program a whole lot simpler to build.
One way we COULD attempt to approach this problem is to rely on our current understanding of Textures and accomplish this task by
finding a rectangular image, and loading it into a Texture.
But what happens when we want to change the color of our current rectangle? What do we do if we want to try to change the shape
of the rectangle as well?
We have to go and change the ORIGINAL image in another piece of image editing software. This would be incredibly cumbersome to
do every time we want to draw a different colored or shaped rectangle.
So what can we do?
Instead of loading a pre-existing image into our Texture, we can just create our Texture manually
1.3 Pixmaps and Textures
We’ve talked about Textures and fair bit so far, and we understand that they are important for drawing things to the screen, but what is a
Texture? Let’s knock out a couple definitions real quick.
Pixel: Computer displays are made of millions of tiny little lights. Each of these lights can shine any color we want. In the software world, a
Pixel is the smallest unit of data that can make one of those lights shine a given color. The color of a pixel is given by its ratio of red, blue, and
green light.
Texture: A Texture is a data structure that holds a bunch of pixel data. Textures are the simplest way of telling our computer how to draw
something to the screen. The computer can loop through all of the pixels in the texture, and light up corresponding lights on the display with
the color given by that pixel data.
If a Texture is just a container for color data, then could we somehow generate our own Textures from scratch?
Can AND will!
Pixmap: A data structure given to us by LibGDX that allows us to generate color data that can be sent to a Texture
https://libgdx.com/wiki/graphics/2d/pixmaps
If we want to create custom Textures, a Pixmap will be the simplest way for us to do just that. Let’s go ahead and look at the constructor we’ll
be using for a Pixmap, then see if we can make one.
We can see that if we want to create a Pixmap, all we have to do is give it a width and a height.
Pixmap rectangleMap;
public void create () {
batch = new SpriteBatch();
img = new Texture("Rectangle.png");
rectangleMap = new Pixmap(200, 100, Format.RGBA8888);
}
Creating a Pixmap that is 200 x 100 pixels
We can now make img use our new Pixmap as the source for all of its pixel data by simply creating a new Texture, and sending in our Pixmap in
the constructor.
We can tell set the color of all the pixels in our Pixmap with the following code
rectangleMap = new Pixmap(200, 100, Format.RGBA8888);
rectangleMap.setColor(Color.BLACK);
for(int x = 0; x < rectangleMap.getWidth(); x++) {
for(int y = 0; y < rectangleMap.getHeight(); y++) {
rectangleMap.drawPixel(x, y);
}
}
img = new Texture(rectangleMap);
Sets the color we’ll be drawing with to black, then loops through every pixel in the Pixmap and draws that color to the pixel
If we run our code now, we should be able to see that our program now displays a black rectangle at the bottom of the screen!
And you can change both the color and shape of the rectangle by just playing with the values we’ve already created
1.3 Rec2D
Now let’s say that we want to scale things up a little, and draw TWO DIFFERENT rectangles to the screen at the same time. We could
replicate the code we’ve already created, but try and guess what I’m going to say is wrong with the following code.
SpriteBatch batch;
Texture img;
Texture imageTwo;
Pixmap rectangleMap;
Pixmap otherRectangleMap;
@Override
public void create () {
batch = new SpriteBatch();
rectangleMap = new Pixmap(50, 500, Format.RGBA8888);
otherRectangleMap = new Pixmap(300, 50, Format.RGBA8888);
otherRectangleMap.setColor(Color.BLUE);
rectangleMap.setColor(Color.GREEN);
for(int x = 0; x < rectangleMap.getWidth(); x++) {
for(int y = 0; y < rectangleMap.getHeight(); y++) {
rectangleMap.drawPixel(x, y);
}
}
for(int x = 0; x < otherRectangleMap.getWidth(); x++) {
for(int y = 0; y < otherRectangleMap.getHeight(); y++) {
otherRectangleMap.drawPixel(x, y);
}
}
img = new Texture(rectangleMap);
imageTwo = new Texture(otherRectangleMap);
}
@Override
public void render () {
ScreenUtils.clear(.4f, 0f, 0.5f, 1);
batch.begin();
batch.draw(img, 350, 0);
batch.draw(imageTwo, 100, 200);
batch.end();
}
Code drawing two intersecting rectangles
This approach doesn’t SCALE well at all. Every rectangle we want to add to our application, we’ll have to write 11 new lines of code. If I want to have
20 rectangles on screen at once, I’ll have to write out 220 lines of code!
package com.mygdx.imageeditor;
So, what data were we using to represent our rectangles before? Let’s take a look back at the code for drawing a single rectangle, and
highlight every piece of data that determines how our rectangle is drawn to the screen.
We are going to want our rectangles to be able to store a width, length, and position (x, y coordinates)
Mathematically, you would say that these numbers represent scalar values in the horizontal and vertical axis. While this approach
might work fine on an intuitive level, values that only work as scalars are actual very limited in terms of use when it comes to computer
graphics. Instead of storing this data in basic ints, we’re going to use a data structure inherited from LibGDX, Vector2
import com.badlogic.gdx.math.Vector2;
public class Rec2D {
public Vector2 Scale;
public Vector2 Position;
}
Vectors for Scale and Position. Each Vector2 contains an X and Y variable we can set
We’re also going to want Rec2D to be able to keep track of color as well. We’ll add a new variable of type Color for this. This one however, we’ll
never need to access from outside of Rec2D, so we are going to make it private. We’ll also need a Pixmap and Texture for each Rec2D as well. This
could be theoretically a little wasteful, but we won’t worry too much about that.
Now create a constructor for Rec2D that accepts two Vector2s for scale and position, and a Color for the color of the rectangle as arguments,
and set the variables in our class equal to these arguments.
Let’s start moving code from ImageEditor over into Rec2D. Move all of the code responsible for creating our PixMap into a new method
inside of Rec2D called generateTexture()
public void create () {
batch = new SpriteBatch();
rectangleMap = new Pixmap(50, 500, Format.RGBA8888);
rectangleMap.setColor(Color.BLUE);
for(int x = 0; x < rectangleMap.getWidth(); x++) {
for(int y = 0; y < rectangleMap.getHeight(); y++) {
rectangleMap.drawPixel(x, y);
}
}
img = new Texture(rectangleMap);
}
Note: When moving the code over, you should also remove all of the constant data from this code, and replace it with the new
variables we created in Rec2D
If everything went well, you should be able to run the following code –
public void create () {
batch = new SpriteBatch();
rectangle = new Rec2D(new Vector2(200, 100), new Vector2(200,200), Color.RED);
}
public void render () {
ScreenUtils.clear(.4f, 0f, 0.5f, 1);
batch.begin();
batch.draw(rectangle.RecTexture, rectangle.Position.x, rectangle.Position.y);
batch.end();
}
Add a new public Vector2 to Rec2D called Velocity, and add a new argument to our constructor
Velocity?
Yes! Velocity! Traditionally, velocity is represented by (meters/second) but we’ll use our Velocity variable to represent (pixels/refresh).
Storing it in a Vector2 will allow us to give our Rec2D a velocity in both the x and y directions
Now when we create a Rec2D, we’re going to need to give it not only a direction to move in, but a scalar value telling it how quickly it is
going to move in that direction
rectangle = new Rec2D(new Vector2(200, 100), new Vector2(200,200), new Vector2(5,0), Color.RED);
rectangle will have a velocity of 5 pixels/refresh along the x -axis
To make our velocity actually affect our Rec2D, all we have to do is add rectangle.Velocity to rectangle.Position every time we call
.render(). We can do this pretty simply with the method rectangle.Velocity.add() which will allow us to add two Vector2s together
This is happening because our program is moving our rectangle to the right INFINITELY, even when it makes the rectangle disappear out of view.
Ideally, what we want to have happen is that our rectangle bounces off the side of the screen, instead of disappearing.
If we are going to disappear out of the right side of the screen, Velocity will become -5 and our rectangle will bounce to the left.
If we’re going to disappear now off the left side, Velocity will become 5 again, bouncing us to the right
So is there some easy way to tell how big the screen is?
Absolutely! We just need to tell our application how big we WANT it to be!
Hop back over to DesktopLauncher.java and add the following code to set the resolution of our screen.
public static void main (String[] arg) {
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setForegroundFPS(60);
config.setTitle("Image Editor");
config.setWindowedMode(584, 480);
584 x 480 is the resolution for 480p. We chose this resolution arbitrarily, but a smaller one will be preferred as it will en sure our program
will run on computer monitors of any size, WITHOUT us having to change how anything is ever displayed
We can now grab the resolution of our application back over in ImageEditor, and save it into a Vector2
public class ImageEditor extends ApplicationAdapter {
SpriteBatch batch;
Rec2D rectangle;
private Vector2 _screenSize;
public void create () {
batch = new SpriteBatch();
_screenSize = new Vector2(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Grabbing the width and height of our application window and saving it
With the size of our screen now stored, we can take a look back at the pseudo-code from earlier
//if(rectangle.position is out of bounds)
// rectangle.velocity.x *= -1;
“Out of bounds” is kind of a vague metric. I’ll replace it with something that will hopefully illuminate why we bothered setting the resolution of our
application and saving it here in ImageEditor.
Go ahead and implement this pseudo-code in your program. Your rectangle should still move to the right, and just when the rectangle is just about
to walk off screen again….
Add an extra check to our if-statement to make sure that this doesn’t happen
Hint: Position.x is negative when we start walking off the left-side of the screen
If successful, you should have something like this
Going left, bouncing right, then starting to go left again (Sorry, Word/PDFs don’t like working together with videos)
If you were successful with this, try adding the same checks, but for the y-axis. If you do this right, you should be able to give your rectangle a y-
velocity, and see your rectangle bouncing around the screen diagonally!
Just for fun, let’s add one final piece of functionality to our bouncing rectangle program. Every time we bounce off the sides, let’s change the color
of our rectangle. To do this, all we should need is a new method in Rec2D called changeColor()
We’re at the end now, so I’ll just give this one to you
public void changeColor(Color newColor) {
_recColor = newColor;
//Regernate our texture using our new color
generateTexture();
}
Now, whenever you hit the side of one of the walls, call rectangle.changeColor(). We’ll also generate a new random Color each time this happens.
rectangle.Velocity.x *= -1;
Random random = new Random();
rectangle.changeColor(new Color(random.nextFloat(), random.nextFloat(), random.nextFloat(), 1));
Generating random red, green, and blue values
I’d also recommend changing our screen-wipe color to black for some better immersion
1.5 Wrapping Up
Last thing before we go. We’ve made a lot of changes to our program by now
Let ’s save everything we’ve done to Github.
Open up Github Desktop and you should see something like this
This entire time, Git has been tracking the changes we’ve made to our project. Any new files that we’ve added can be seen with a green “+” icon.
Any files that we edited (both added and removed content) are shown with a yellow “.”. Before we upload anything, we can review what we’ve done
to the codebase since the last time we uploaded anything.
In my case, I added two .pngs while I was working on demonstrations for this instruction manual. I don’t actually want to upload those files to my
repository as they were just testing files that I was working with temporarily. I want to remove them now before uploading.
Now, I COULD try and track these files down and delete them manually, if I wanted, but Git makes this a lot easier. I can click on the checkbox to say
that I don’t want to upload it, and the file will remain in the project, but won’t be uploaded.
Or, I could right-click and select Discard changes… and this will delete the files for me.
Now I’ll write a commit message and description of what I’ve done
Now, I’m ready to upload all of my changes. But first, let’s talk very briefly about what Github is actually doing here.
Git Pipeline
In brief, I promise!
Lastly, click Push origin in the top-left, and our changes will be sent out to Github
CONGRATULATIONS!
The first step is always the most difficult, but you’ve made it! We’ve a long way ahead, but all of you who’ve made it here, you should feel proud of
what you’ve already built.