0% found this document useful (0 votes)
13 views

FinalProject_Checkpoint3

Uploaded by

Bo Stevens
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

FinalProject_Checkpoint3

Uploaded by

Bo Stevens
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

CS-2810 Final Project

- Checkpoint 3

Checkpoint Description
So far, we’ve created the basic structure necessary for simple interactivity. In this checkpoint, we are going to begin working on the image
editing functionality of our application. This entire checkpoint focuses almost entirely on a single feature-set.

The Edit Window

The edit window will be where we will be able to see and edit images in our application. It is going to be the most fundamental piece of
functionality for our program, so we’re going to focus entirely on getting a basic version of it up and running.

The Edit Window is where we’ll be doing all of our image processing and doodling

Objectives
1. Objective 1
2. Objective 2
3. Objective 3

Objective 1

Objective checklist:
• Clean up our code from last time
o Make rendering scale better by shoving everything into an Array

1.0 Making Things Easier


We’re going to get started by cleaning up some loose ends from the previous checkpoint. Right now, your rendering code probably looks something
like this-
batch.begin();
batch.draw(button1.RecTexture, button1.Position.x, button1.Position.y);
batch.draw(button2.RecTexture, button2.Position.x, button2.Position.y);
batch.draw(button3.RecTexture, button3.Position.x, button2.Position.y);
batch.draw(button5.RecTexture, button4.Position.x, button4.Position.y);
batch.draw(button5.RecTexture, button5.Position.x, button5.Position.y);

I’ve introduced the idea before that it is bad practice to have copy-paste lines like this, but what’s honestly so bad about the code above?
Perhaps consider, that if I run this code, that this is what my program looks like.

YOU’VE BEEN TRICKED! THIS CODE IS ACTUALLY BROKEN

This is happening because, in all my copy-pasting madness, I forgot to properly change some of my variables. Can you spot where I messed up
above? If not, or if you want to see if you’re right, I’ve highlighted the mistakes below.

batch.draw(button1.RecTexture, button1.Position.x, button1.Position.y);


batch.draw(button2.RecTexture, button2.Position.x, button2.Position.y);
batch.draw(button3.RecTexture, button3.Position.x, button2.Position.y);
batch.draw(button5.RecTexture, button4.Position.x, button4.Position.y);
batch.draw(button5.RecTexture, button5.Position.x, button5.Position.y);
This is dramatically more common than you would think

Let’s go ahead and fix this.


Perform the following -
• Create a public Array called Rectangles inside of ImageEditor of type Rec2D.
o Import Array if needed
• Go to your constructor for Rec2D
o Add “this” to your Rectangles Array somewhere in the constructor
o To access Rectangles, you can use ImageEditor.Instance
o Now every time we create a Button, it will be added automatically to
our list of Rectangles

Then, inside render(), you can create a loop that renders out all of our rectangles for us.
Rec2D rec;
for(int i = 0; i < Rectangles.size; i++) {
rec = Rectangles.get(i);
batch.draw(rec.RecTexture, rec.Position.x, rec.Position.y, rec.Scale.x, rec.Scale.y);
}

Why save Rectangles.get(i) into a variable?


This is a small typing optimization. Rectangles.get( ) 16 characters, and rec is only 3. It helps the following call to batch.draw() fit all on
one line neatly.

Everything drawing in the correct place again


Objective 2

Checklist:
• Create more interactive elements for our Button class
o Hovering over
o Unhovering
o Clicking up
• Make InputManager activate the interactive code we’ve put inside Button

2.0 OnHover
Before moving on to the edit window, let’s take a look at some more of the code from the previous checkpoint, and expand the capabilities of our
code a little. As-is, it’s a little difficult to tell when a button has been pressed.

Sure, we’re printing out to the console window, but the console isn’t coming along with us when we package things up as a .jar file for other people
to run.

So what can we do?


We can make our buttons appear more interactive by changing the way they LOOK when we interact with them!

We’ll do this by creating behavior that can change the _recColor of a Button whenever it has been clicked on or hovered. We can start by adding a
method to our Button class, called onHovered().

public void onHovered() {


System.out.println("You're hovering over " + _buttonNumber);
}
We’ll call this method once we’ve determined if a button is currently being hovered over by the mouse
So, how can we tell when a button has been hovered on?
We can actually utilize an already existing method inside of InputManager.java called mouseMoved

Perform the following:


• Go into mouseMoved() inside of InputManager
• Call CollisionManager.Instance.getCollision
o This should look IDENTICAL to how you did it in touchDown()
• If your mouse did collide with something, call .onHovered() on what you collided with
public boolean mouseMoved(int screenX, int screenY) {
//When the mouse is moved, determine which (if any) Button the mouse has collided with
//If it did collide with a Button, go ahead and call .onHovered();
return true;
}
Pseudo-code for the task you’re trying to achieve

Your expected output

Now, so far, this is cool and all, but we just mentioned that the console window isn’t a good way of showing information to our users, so instead of
printing a message, let’s change the color of our Button when it’s been hovered over!

To do this, we’re going to need to edit _recColor. Button inherits from Rec2D, but doesn’t have access to _recColor as it’s private. A getter/setter
could be used, but I’ll just try to keep some amount of control over access to this variable by setting it to protected. (As I’m lazy)

protected Color _recColor;


Further reading if this doesn’t make sense:
https://www.w3schools.com/java/ref_keyword_protected.asp

Now, when onHovered() is called, we can modify the color of our Button to be twice as dark. This is quite trivial to do, as the rgb values of a Color all
get darker as they approach 0.

Public void onHovered() {


System.out.println(“You’re hovering over “ + _buttonNumber);
_recColor = new Color(_recColor.r / 2f, _recColor.g / 2f , _recColor.b / 2f, 1);
}
Sets the rgb values of a Button to half their brightness
Go ahead and run your program, and you should see that hovering now does

…nothing

This is because of our approach to building our Textures. When we create our Button, we call generateTexture() up in Rec2D. Recall that this is the
method where we draw in the color-data of our Texture. Changing the variable we used for color unfortunately doesn’t change that underlying
color-data that we painted in.

HOWEVER

We can just call generateTexture() again after changing the color, and it will set all of your pixel-data to this new Color!
_recColor = new Color(_recColor.r / 2f, _recColor.g / 2f , _recColor.b / 2f, 1);
generateTexture();

NOTE: This operation is VERY expensive to run, as we regenerate our Texture every single frame that our mouse is hovering
over our Button. It is NOT recommended that you use this exact approach in-industry for this reason. We’re choosing it only
for the sake of simplicity.

And now! We can see!

Textures turning black after being hovered over

So what’s going wrong now?


Every frame we hover over a button, we divide it’s rgb components in half. Our pixel data therefore VERY quickly approaches (0,0,0,1)

Our problem is that we only want to set our Rec2Ds Color to half of its ORIGINAL value, but we keep overriding our data, making it darker and
darker. We can fix this by using a variable that keeps track of the original color of our Rec2D
private Color _startColor;
public Button(Vector2 scale, Vector2 position, Color recColor) {
super(scale, position, recColor);
_startColor = recColor;

Now, as long as we NEVER change the value of _startColor, we can safely use it in our onHovered() method to change _recColor.
_recColor = new Color(_startColor.r / 2f, _startColor.g / 2f , _startColor.b / 2f, 1);
Replacing _recColor / 2f with _startColor

Now open up your program again, and try hovering over your Buttons, and they should change color properly!

Our buttons stay permanently dark after being hovered over.

…until we move our cursor off the Button that is.


Rats!

So what are we missing?

2.1 OnHoverExit
Right now, our system is only capable of detecting when a Button has been hovered over, but it has no concept of when we have STOPPED hovering
over an item with our cursor.

This is what’s responsible for our current behavior.

If we only knew when a Button is no longer being hovered over, we could tell it to return back to its _startColor.
So let’s add a new method to Button, called onHoverExit() to do exactly this, and have it set the current _recColor back to _startColor.
public void onHoverExit() {
_recColor = _startColor;
generateTexture();
}
When this method is called, we set our Button back to its original color.

Now all we need to do is figure out HOW to determine that our mouse has EXITED the bounds of a Button

The following are rules that we can use to tell when a Button has become “unhovered”

• When the mouse is over blank space, nothing is hovered


• When the mouse collides with a Button, that Button becomes hovered
o As long as the mouse stays here, the Button will remain hovered
• When the mouse moves to either another Button, or empty space, the Button that WAS hovered,
should be marked as unhovered
o This requires our program to understand both of the following
▪ Is the mouse hovering anything RIGHT NOW
▪ Was the mouse hovering anything PREVIOUSLY

Mouse hovering nothing, then hovering the Blue Button once moved, then after moving off the Blue Button, the Blue Button becomes
unhovered

To implement this behavior -


Perform the following:
• Hop over to InputManager.java
• Add a private instance variable called _currentlyHovered of type Button
o To “unhover” a Button, it will first need to be hovered
o Having a variable to keep track of this will make things easy for us
• In mouseMoved, set the value of _currentlyHovered to whatever we collided with, at the
BOTTOM of the method
o It’s important that this happens at the end, as you’ll hopefully see
• When _currentlyHovered is NOT null, and has a DIFFERENT value than whatever you
collided with, call _currentlyHovered.onHoverExit()
o Do this BEFORE setting _currentlyHovered equal to whatever you collided with

You will know that you have succeeded when you can recreate the behavior in the screenshots from above

Hurray! We can now tell when a Button has been hovered over with the mouse

2.2 On Click Down/Up


Our program still doesn’t provide any visual feedback for when a Button has been clicked beyond a simple print statement. Let’s add some more
visual flair to make it obvious when a Button has been clicked.

A very simple way of doing this is to simply make the Button DARKER when we click on it. Darker even, than when we’ve hovered over it.
Perform the following:
• Hop into onPressed(), in InputManager.java
• Set the Color of your Button to 1/4 of its original brightness.
If you do it right, you should see that your Button goes even Darker once clicked!

The Blue Button goes from being hovered, to clicked, becoming even darker

However, if we keep our mouse perfectly still after letting go, our Button remains the same “clicked” color

This is happening because our code lacks the ability to understand when a Button has become “unclicked”. It only changes color when we move the
mouse because onHovered() is getting called. We can fix this by adding a new method to handle when a Button has become “unclicked”

Perform the following:


• Go to Button.java
• Add onClickUp(Vector2 clickPosition)
• Change onPressed() to onClickDown(Vector2 clickPosition)
o This is to be more consistent with our naming scheme
o Note that our “click” methods now take a Vector2
• Add a private instance variable called _hoveredColor of type Color to Button.java
o Set it to (startColor.r / 2f, startColor.g / 2f, startColor.b / 2f, 1);
o Use this variable inside onHovered() instead of the line currently setting the
color of _recColor
• Make it so onClickUp() sets the color of the Button to _hoveredColor
• When both onClickDown and onClickUp are called from InputManager
o Send them the Vector2 you used for collision detection
o This might seem odd, but it WILL BE USED later.

The following should give you the code we’ll need to change our color again when we “unclick” a Button. However, we still have to call onClickUp()
to make our code do anything new.

Perform the following:


• Go to InputManager.java
• Find the method touchUp()
• If our mouse is hovering over something, call onClickUp()
o A Button can only be clicked if it is currently hovered
o We can reuse our _currentlyHovered variable
o If _currentlyHovered isn’t null, call _currentlyHovered.onClickUp()
• Add code that calls _currentlyClicked.onClickUp() inside if _currentlyClicked
is not null

If all went successful, you should now be able to click away to your heart’s content on your Buttons!

Hovering, clicking down, clicking up

Unless….
We move our mouse around while holding down a click. Then our Button doesn’t update anymore.
If we move our mouse off the Button that we clicked on, it stays dark.

This happens because LibGDX, being a multiplatform library, splits up moving the mouse, and dragging a clicked mouse (largely because touch-
dragging is a big deal in mobile) To get started fixing things –
Perform the following:
• Go to InputManager.java
• Find touchDragged()
• Make it call mouseMoved()
o Pass screenX and screenY into mouseMoved()

And this will


Break things a little…

Now our Button’s behavior is all kinds of messed up!

Hang in there everyone! This is the last step, I promise!

This is because now we’re overriding the fact that our Button is clicked whenever our mouse is moved. The way to fix this is to add the concept of
STATE to our Buttons. If a Button can REMEMBER that it is currently being clicked, it can stop itself from overriding the color of the Button when
onHovered() gets called.

The easiest way to do this, is to tell our code that a Button can be either clicked on or hovered over
But NEVER both at the same time.

There are a number of ways we can do that, but we’ll be taking the approach of using enums, as they’re easily scalable, and very human readable.

public enum ButtonState {Clicked, Hovered, None};


private ButtonState _state;
Add these lines to Button

To make our Button perform as expected, perform the following.

• Set _state to ButtonState.None when the Button is created.


• Set _state to Clicked when the Button has been clicked.
• If _state is Clicked, then make onHovered() exit immediately before doing anything
• If you CAN hover over a Button, set its state to Hovered
• When you move your mouse off of a Button, set the state to None again.
• Lastly, let’s fix up our code to avoid unnecessarily calls to generateTexture()
o In onHovered() if the state is already Hovered, don’t do anything!
o In onClickDown(), if the state is already Clicked, return IMMEDIATELY!

And hurray!

If you hover over a Button, it goes dark (50% original brightness)


If you click on a Button, it goes darker (25% original brightness)
When you unlick a Button, it goes from darker back to dark (50% original brightness)
If you DRAG while clicked, the Button goes from darker to full color (100% original brightness)

2.3 Testing
To verify that your code is working, you should now be able to get the following results in your program:

Hovering and unhovering the blue Button


Hovering, Clicking Down, and Clicking Up (Releasing the click) on the blue Button

Hovering, Clicking Down, Unhovering (While still holding click)

Objective 3

Checklist:
• Build an Edit window to draw doodles on
o Create EditWindow.java
o Give it a Texture to draw doodles to
• Rewire our input management
o Make our program able to have any class pick and chose “how” it can be interacted with
• Fix up our ability to draw a little by letting us “drag” across our edit window

3.0 EditWindow.java
Alright! Finally! It’s time to work on some actual functionality that ISN’T just general setup. Let’s start by removing the Buttons that we have already
created, as they won’t be any particular use to use going forwards.
Button button1;
Button button2;
Button button3;
Button button4;
Button button5;
SpriteBatch batch;
public void create () {
Instance = this;
InputManager inputManager = new InputManager();
Gdx.input.setInputProcessor(inputManager);
batch = new SpriteBatch();
ScreenSize = new Vector2(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Vector2 rectangleScale = new Vector2(100,100);
button1 = new Button(
rectangleScale,
new Vector2(ScreenSize.x / 2f - rectangleScale.x * 2, ScreenSize.y / 2f - rectangleScale.y * 1.5f),
Color.ORANGE);
button2 = new Button(
rectangleScale,
new Vector2(ScreenSize.x / 2f + rectangleScale.x, ScreenSize.y / 2f - rectangleScale.y * 1.5f),
Color.GREEN);
button3 = new Button(
rectangleScale,
new Vector2(ScreenSize.x / 2f + rectangleScale.x, ScreenSize.y / 2f + rectangleScale.y / 2f),
Color.BLUE);
button4 = new Button(
rectangleScale,
new Vector2(ScreenSize.x / 2f - rectangleScale.x * 2, ScreenSize.y / 2f + rectangleScale.y / 2f),
Color.RED);
button5 = new Button(
rectangleScale,
new Vector2(ScreenSize.x / 2f - rectangleScale.x / 2f, ScreenSize.y / 2f - rectangleScale.y / 2f),
Color.WHITE);
Removing all references to our Buttons , giving us an EMPTY program
Let’s also get rid of the print statement inside of our Button class
public class Button extends Rec2D implements IClickable, IHoverable {
private static int _buttonCount;
private int _buttonNumber;

public Button(Vector2 scale, Vector2 position, Color recColor) {
_buttonCount +=1;
_buttonNumber = _buttonCount;

}
public void onClickDown(Vector2 mousePosition) {

System.out.println("You've pressed button " + _buttonNumber);
}
All references to _buttonCount and _buttonNumber removed from the program.

The final big goal for this checkpoint is going to be creating a basic editing window that we can draw crude little doodles on. Since this is going to
eventually require a lot of unique functionality, we are going to create a brand-new class, EditWindow.java.

Our edit window is going to be an interactive element, so for now, we are also going to have it extend Button, as that’s the only class we have set up
that can handle user input.
public class EditWindow extends Button{
public EditWindow(Vector2 scale, Vector2 position, Color backgroundColor) {
super(scale, position, backgroundColor);
}
}
Calling the constructor for Button inside our new EditWindow class

We can now create our EditWindow in ImageEditor.java


private EditWindow _editWindow;
public void create () {
Instance = this;
InputManager inputManager = new InputManager();
Gdx.input.setInputProcessor(inputManager);
batch = new SpriteBatch();
ScreenSize = new Vector2(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Vector2 editWindowSize = new Vector2(500, ScreenSize.y - 50);
_editWindow = new EditWindow(
editWindowSize, new Vector2(ScreenSize.x - editWindowSize.x, 0), Color.GRAY
);
CollisionManager collisionManager = new CollisionManager();
}

And we should see that our window looks something like this

This shape was chosen to leave some space for future items we’ll be adding

Now, our Edit Window is going to be eventually doing a WHOLE LOT more than just a basic Button, so let’s override some of the methods of Button,
so we can eventually add our own functionality.
public EditWindow(Vector2 scale, Vector2 position, Color backgroundColor) {
super(scale, position, backgroundColor);
}
public void onClickDown(Vector2 clickPosition) {
super.onClickDown(clickPosition);
System.out.println("Clicked on the Edit Window");
}
super is the keyword that calls anything in the parent class

If you click on your EditWindow, you should now see a message in your console, confirming that our EditWindow code is running.
Woo!

Didn’t we just spend a bunch of effort to remove any code dealing with the console window?
And that’s why we’re going to immediately remove it! I just wanted to make sure that everything is functional before going forwards.

Now, for today, we’re not going to go very far with the Edit Window, but let’s get some basic functionality working. Let’s make it so that we can draw
some doodles on top of our window.

So, this begs the question-

How do we do that?
Would it surprise you to know that we can do it without any new tech or structure than what we’ve already covered?

To draw on top of our Edit Window, we’ll use the same tech we’ve been using so far to draw everything else, a Pixmap and a Texture.
Add the following to your EditWindow
public class EditWindow extends Button{
public Texture DoodleTexture;
private Pixmap _doodleMap;
public EditWindow(Vector2 scale, Vector2 position, Color backgroundColor) {
super(scale, position, backgroundColor);
_doodleMap = new Pixmap((int) scale.x, (int) scale.y, Format.RGBA8888);
_doodleMap.setColor(Color.ORANGE);
DoodleTexture = new Texture(_doodleMap);
}
Creating a Pixmap of the same dimensions as the Edit Window itself

Now when the user clicks on our EditWindow, let’s draw over the pixel they clicked on.
public void onClickDown(Vector2 clickPosition) {
super.onClickDown(clickPosition);
System.out.println("Clicked on the Edit Window");
_doodleMap.drawPixel((int) (position.x),(int) (position.y));
DoodleTexture = new Texture(_doodleMap);
}

Now let’s also draw our little doodle in our render() method.
for(int i = 0; i < Rectangles.size; i++) {
rec = Rectangles.get(i);
batch.draw(rec.RecTexture, rec.Position.x, rec.Position.y, rec.Scale.x, rec.Scale.y);
}
batch.draw(_editWindow.DoodleTexture, _editWindow.Position.x,
_editWindow.Position.y, _editWindow.Scale.x, _editWindow.Scale.y);
Note how we’re drawing our doodle AFTER we’ve drawn everything else.

WARNING: If you suffer from epilepsy, either click slowly, or perhaps better yet, skip some of the following testing steps as there WILL be flashing imagery
If you try running our program, you can now see that whenever you click, orange little dots will show up on the screen.

A bit small, aren’t they?


But our pixels are all showing up in weird spots, aren’t they?
THEY ARE!

Our pixels don’t show up where our mouse is pointing. This is because our position variable tells us where on our screen, our mouse is pointing,
NOT where on our Pixmap we should be drawing in pixels.

Two things are to blame:

ONE: Our Pixmap starts at an X-Position of 84. If I click on the left-most pixel of my edit window clickPosition would have an X-value of 84. Our code
as-is, then moves 84 EXTRA pixels to the right, and places an orange pixel there
TWO: Our world-coordinates have a Y-Value of 0 at the bottom of the screen. A Pixmap has a Y-Value of 0 at the top of the Pixmap

The screenshot below demonstrates this problem:

Blue represents world-coordinates


Green represents Pixmap-coordinates

Clicking on (50,200) will place an orange pixel 50 pixels to the right, and 200 pixels down from the TOP-LEFT corner of our Pixmap

Let’s go ahead and fix this!

Perform the following-


• Subtract clickPosition by the X-Position of the EditWindow
o If done right, this should subtract by 84
o DON’T use a constant value. Use the actual Position variable.
• Reverse your y-coordinates
o EditWindow HEIGHT Subtracted by clickPosition.y

After performing the above steps, you should be able to draw dots EXACTLY where your cursor is pointing.

3.1 Breaking Down, Building Out


You’ve probably noticed that whenever we click down on our Edit Window, it flashes color and becomes darker for a moment. This is because of the
code we’ve inherited from Button. We set up all of our Buttons to change color when hovered and when clicked on.

But…maybe we don’t actually WANT these features in our Edit Window

In this case, the features we’ve gained from Button are actually providing BLOAT to our program in terms of unnecessary and unwanted features. To
fix this, we are going to decouple the way we process user input.

Why?

We WANT to be able to click on our Edit Window


But we DON’T want our EditWindow itself to change color when we hover/click/unclick/unhover

Okay, so how do we do it?


Create two new files. IClickable.java and IHoverable.java. Change them both from classes to interfaces. All of the methods we’ve been using to track
input in our Button class are going to go inside these files.
public interface IClickable {
public void onClickDown(Vector2 clickPosition);
public void onClickUp(Vector2 clickPosition);
}

public interface IHoverable {


public void onHovered();
public void onHoverExit();
}

Why are we prefixing these files with an “I”?


This is another bit of styling I personally like to use. These files are interfaces, so I mark their names with an “I” at the beginning. It simply
makes things easy to keep track of. It’s not at all necessary for you to do this yourself, but consider it a mild recommendat ion.

Okay, and why are we creating interfaces?


We want to be able to “pick and choose” in which ways any object wants to interact with our input system. The fact that we ca n inherit as
many interfaces as we want is going to make things very nice for us.

While we can perhaps solve our current issue by other means, decoupling our code in this manner will give our codebase much more flexibility in
the long term as we continue adding features.

If I don’t want my Edit Window to do anything when it’s been hovered over, I’ll just choose not to implement IHoverable.
That’s the idea, but we’ve still got some work to do until this becomes possible!

We can now edit Button to implement both IClickable and IHoverable


public class Button extends Rec2D implements IClickable, IHoverable {
I’m implementing both because I want a button to be both clickable and hoverable

Let’s also change up our EditWindow. We’ll no longer make it extend Button, and we’ll also have it implement JUST IClickable
public class EditWindow extends Rec2D implements IClickable{

public void onClickDown(Vector2 position) {
System.out.println("Clicked on the Edit Window");
super.onClickDown(Position);
_doodleMap.drawPixel((int) (position.x - Position.x),(int) (Scale.y - position.y));
DoodleTexture = new Texture(_doodleMap);
}
@Override
public void onClickUp(Vector2 mousePosition) {
// TODO Auto-generated method stub
}
Note how implementing IClickable has forced us to add an onClickUp method
Why are we now extending Rec2D
We wanted to get rid of some of the special features of buttons, but remember earlier that we set our program up to ONLY be able to draw
rectangles. There are still plenty of features of Rec2D that we want to actually keep.

And hurray! If we now open our program and mouse over our Edit Window

It….does nothing

This is because our InputManager still expects everything interactable in our program to still be of type Button. We however, now have items we
want to interact with that could be of any kind of class at all!
Just as long as those classes implement either IClickable or IHoverable

Hmmm….

So, what if, instead of keeping something like an Array of type Button, we had TWO Arrays, of type…

IClickable and IHoverable

Well, then we could rewire our InputManager to make use of any data type in the world, just as long as it’s marked as either clickable or hoverable.

Perform the following-


• Add public arrays of type IClickable and IHoverable to InputManager
• In the constructor for EditWindow
o Add “this” to InputManager.Instance.Hoverables
• In the constructor for Button
o Add “this” to both Clickables AND Hoverables
• Change _currentlyHovered to type IHoverable in InputManager
• Add a private variable called _currentlyClicked of type IClickable to InputManager
o Assign it the result of your collision inside of touchDown()
o Use that value in touchUp() to call _currentlyClicked.onClickUp()
• Add methods to CollisionManager: getHovered(Vector2) and getClicked(Vector2)
o These methods will have a return type of IHoverable and IClickable respectively
o Each method will loop through one of the two Arrays created previously to find
which item the coordinates collide with

If you do this, you might reach a stage where your code looks something like this-
Our collision detection algorithm depends on access ing a variable called Position, which doesn’t exist in either of our interfaces
Let ’s do a bit of a sneaky hack. Bear with me on this one

Recall that I mentioned it would be VERY important that EVERYTHING in our program be made up of Rectangles?
Well, what kind of objects are going to be stored in either of these arrays?
Rectangles!
I mean, yeah, Buttons and our EditWindow
But guess what both of those classes inherit from?

Rec2D

This is INCREDIBLY important, because it lets us get away with things that would normally cause our code to crash
If we know ahead of time that everything in both of these Arrays is actually a Rec2D, we can CAST any item from these arrays to a Rec2D
public IHoverable getHovered(Vector2 coordinates) {
Rec2D hovered;
for(int i = 0; i < InputManager.Instance.Hoverables.size; i++) {
hovered = (Rec2D) InputManager.Instance.Hoverables.get(i);
if(coordinates.x > hovered.Position.x && coordinates.x < hovered.Position.x + hovered.Scale.x) {
if(coordinates.y > hovered.Position.y && coordinates.y < hovered.Position.y + hovered.Scale.y)
return (IHoverable) hovered;
}
}
return null;
}
Is your mind exploding? I hope it ’s exploding right now

Now Perform the following-


• Fill out getClicked()
o It should loop through Clickables, and return an IClickable
• Replaces calls to getCollided() with getHovered() and getClicked()
o DELETE getClicked() and your Buttons Array
• Add a button in the bottom-left of your program (of any size, color, and scale you want)
o It’s just going to be for testing

After performing all this, you should now be able to paint pixels onto your EditWindow without the entire window wildly changing color.

Edit Window should no longer be flashing as we paint in little dots

You should also still be able to hover over and interact with your Button as before. You’ve done everything correctly if you can see the following
results from performing the listed operations.

Hovering, Unhovering, Clicking Down, Clicking Up, Clicking Down then Unhovering then Clicking Up

NEAT!
3.2 Improving Our Drawing Ability
So far, we’ve created a TON of Button functionality, and also created a canvas upon which we can now paint.

Very….very slowly…

Each time we click down, we add only a SINGLE pixel, to our little canvas. Let’s change this and add some functionality to our interactable items for
when we drag a clicked mouse across their surface.

THIS IS THE LAST THING ! I PROMISE YOU

Add a new method to IClickable called onClickDragged()


public interface IClickable {
public void onClickDown(Vector2 clickPosition);
public void onClickUp(Vector2 clickPosition);
public void onClickDragged(Vector2 clickPosition);
}
Aren’t interfaces just neat?

This will cause both EditWindow and Button to error out. Hop in and override onClickDragged() in each class.
public class EditWindow extends Rec2D implements IClickable{

@Override
public void onClickDragged(Vector2 clickPosition) {
// TODO Auto-generated method stub
}
You can get rid of the @Override if you want

Now, we have a method that we can call when we have dragged a clicked mouse across the surface of our EditWindow. We can call our new
onClickDragged method as follows
public boolean touchDragged(int screenX, int screenY, int pointer) {
mouseMoved(screenX, screenY);
if(_currentlyClicked != null)
_currentlyClicked.onClickDragged(new Vector2(screenX, ImageEditor.Instance.ScreenSize.y - screenY));

We can verify that this is working by making the version of onClickDragged in EditWindow do a little painting.
private void paintAtPosition(Vector2 worldPosition) {
_doodleMap.drawPixel((int) (worldPosition.x - Position.x),(int) (Scale.y - worldPosition.y));
DoodleTexture = new Texture(_doodleMap);
}
public void onClickDragged(Vector2 clickPosition) {paintAtPosition(mousePosition);}
public void onClickDown(Vector2 clickPosition) {paintAtPosition(position);}
I’ve restructured onClickDragged and onClickDown here to avoid any copy-pasting

What about the onClickDragged inside of Button.java?


Leave it empty! This is one of the advantages of splitting up our input into interfaces like we have. We don’t really want to do anything
when the user click-drags across a Button. If we treated those as full clicks, we could accidentally end up clicking a Button THOUSANDS of
times when we probably only meant to do it once

3.3 Testing
With this change implemented, when you drag your mouse (slowly) across the EditWindow, you should see a nice solid line show up!

If you can do this in one click, then your code is GREAT


If you can do this, and your Button reacts properly to being both clicked and hovered, then congratulations!

You completed another checkpoint!!!

Congratulations are definitely in order here! This checkpoint had a couple of sections where you had to do some extending programming without
any assistance. Maybe it wasn’t a problem at all, and maybe you had to put a lot of work into those sections.

Either way, take your burgeoning problem-solving ability within the confines of this project as the progress that it is!

There are still many ways in which you could consider this program basic, but today, you achieved bringing forth one of the most core pieces of
functionality to this project.
From here, you can look forwards to deepening the abilities of our young application by adding things like the ability to change colors, the
functionality to fix the jaggedness of the lines we draw, and more.

Remember to upload your changes to Github


(fyi It looks great to recruiters to see a solid amount of history on your Github profile)

You might also like