Let's Make a Thing (Twitter4j)

 

Let's Make a Thing (Twitter4j)

So this is my nod of goodbye to LibGDX. As of after this project I will bid it farewell and move on to the land of C++ and its extensive set (list?) of libraries. It has been a good run, I’ve used LibGDX since my final year project at Newcastle University, which was way back in the late 2013. One of the reasons for moving is my decision to get out of my Java-flavoured comfort zone and get better at C++. Plus, I think ‘We Are Alive’ would benefit greatly from the move. Anyway…

I made a thing, it’s called ‘To Deep Fore Me’, you can try it here.

Prep

So on Sunday I sat down, leafed through my list of projects I wanted to try and came across ‘To Deep Fore Me’. The concept was written down thusly: it’s night, the stars are shining and we are walking contemplatively to atmospheric music as #deep tweets fly across the sky. Cool.

Where Do We Start?

Well, we start with a realization that tweets with the hashtag #deep are not safe for work. So we decide to use #deepthoughts instead. Then we figure out which libraries to use.

Since this project was more about messing around with Twitter stuff, we can use LibGDX for the game element of the project, since it won’t throw any surprises. As for Twitter stuff - quick googling showed that for the simple thing I want to do (grab tweets with a specific hashtag) - Twitter4j is the way to go.

Now it’s time to grab a whiteboard marker and plan everything out, since I don’t want to lose the whole of Sunday to the project (spoiler alert: I lost the whole of Sunday to the project).

Here’s what we need to do and how long it might take (shamelessly copied from my whiteboard):

  1. Create a simple empty LibGDX project, create a git repository to accommodate it (~30 minutes)
  2. Import Twitter4J, write code that will grab a certain number of tweets and store them (~1 hour)
  3. Write level code: key listeners, tweets floating past the screen, number of tweets per unit of screen (~1 hour)
  4. Draw graphics and stick them into the level: create texture objects, sort out scrolling (~1 hour)
  5. Just kind of play around with the results until I’m happy, little tweaks, cleaning up the code, etc (~1 hour)
  6. Build a jar (~5 minutes)

My estimation was a bit off - ‘To Deep Fore Me’ took roughly six and a half hours (minus breaks) to do from start to finish. For one, turns out I’m not as skilled with gradle as I thought, also other little bits and bobs like drawing, photoshopping, and tweaking the scrolling - took a bit of additional time. Still was fun though.

How Does It All Fit Together?

Snuggly.

Twitter Stuff

To make it easier to move tweets around the screen - let’s create a TweetObject that will contain the text, coordinates and the movement speed of a tweet (with some getters and setters, not pictured).

    public class TweetObject {
        private String text;
        private Vector2 position;
        private int speed;
		
		// not actual code
		public void setStuff(..);
		public Something getStuff(..); 
    	
    }

When creating a ‘level’ - use TwitterLogic to connect and grab, say, 500 tweets with the hashtag #deepthoughts, stick each into an arraylist of String.

Turns out there’s a limit on the amount of requests you can make, which is something like 15 requests in 15 minutes or something, who cares? It’ll be a bummer if we launched the game several times, exceeded our limit, and now the night sky isn’t filled with awe-inspiring tweets, so to not take away from the experience - let’s just stick some sort of a default totally-not-made-up tweet in the array and use that if we can’t get any actual tweets (for more refer to the populateWithTestData() method of TDFMLevel).

    public static String getRandomTweet() {
	    if (tweetsList.isEmpty()) {
	        return "How can mirrors be real when our eyes aren't real?";
	    } else {
	        Random randIndex = new Random();
	        int index = randIndex.nextInt(tweetsList.size() - 1);
	        return tweetsList.get(index);
	    }
    }

LibGDX Side

Then on the game side we want another arraylist, this time of type TweetObject. Let’s say we want no more than twelve tweets on the screen at one single time.

So after we grab the 500 tweets from Twitter and stick them into an array - we call getRandomTweet() until our arraylist size is 12. While we’re hunting for new tweets - they come in as strings - we are sticking them into new instances of TweetObject, giving them a random ‘y’ coordinate (making sure that it will never be in the section of the screen where our contemplative hero is walking - this part of the solution is a bit hacky, it’s hardcoded) and an ‘x’ value which will either place it on the right side or the left side of the screen. The side depends on whether our intrepid hero was walking left or right. The speed is assigned randomly in the constructor of TweetObject, values are in the range between 1 and 6.

    private void addNewTweets(boolean movedRight, boolean firstRun) {
	    while (tweetsOnScreen.size() < Integer.parseInt(Utils.numberOfTweetsOnScreen)) {
	        String tweetText = TwitterLogic.getRandomTweet();
	        layout.setText(font, tweetText);

	       Random rand = new Random();
	       int y = getY(rand);
	       int x = getX(movedRight, firstRun, rand);

	       TweetObject aTweet = new TweetObject(tweetText, new Vector2(x, y));
	       tweetsOnScreen.add(aTweet);
	    }
    }

We keep track of our tweet coordinates when moving them around and as soon as one of them ends up off-screen - we delete it and call addNewTweets() again, since it picks random tweets - they might well be the same ones we’ve already seen, this is easy to fix, but we won’t because it’s not Sunday anymore.

    public void updateTweets(boolean movingRight) {
	    Iterator<TweetObject> iter = tweetsOnScreen.iterator();

	    while (iter.hasNext()) {
	        TweetObject aTweet = iter.next();

	        if (movingRight) {
		        aTweet.moveRight();
	        } else {
		        aTweet.moveLeft();
	        }

	        layout.setText(font, aTweet.getText());

	        if (aTweet.getPosition().x > Gdx.graphics.getWidth() || aTweet.getPosition().x + layout.width < 0) {
		    iter.remove();
	        }
	    }

	    addNewTweets(movingRight, false);
    } 

The rest is even more straightforward.

The background (stars and the moon) are static, we just create a texture and draw it in the same position till the end of time.

Our rich-in-backstory hero is fixed in place in the middle of the screen, we have a spritesheet with five drawings of him in different stages of walking and an Animation object (courtesy of LibGDX) that shifts the current frame to the next one when we’re pressing an arrow-key and a specific amount of time passes (0.15f to be exact). If the user decides to walk in the opposite direction - we flip the image horizontally and adjust it.

TextureRegion currentFrame = walkAnimation.getKeyFrame(stateTime, true);
batch.draw(currentFrame,
		   walkingRight ? (Gdx.graphics.getWidth() / 2)
			            : (Gdx.graphics.getWidth() / 2) + currentFrame.getRegionWidth(),
		   groundStart - 30, walkingRight ? currentFrame.getRegionWidth() : -currentFrame.getRegionWidth(),
		   currentFrame.getRegionHeight());

The road that the little guy is walking on is not static, it’s a giant texture (roughly four times the width of the screen).

The way it is set up is: there are three instances of the road texture, we are seeing the middle one, then there’s an instance to the left of the middle one and an instance to the right. They all scroll at the same time when the player presses the arrow buttons, when the whole of the middle texture ends up off-screen to the left (it essentially takes left texture’s initial position) - it becomes the left texture, the right becomes the middle texture and the left becomes the right texture. If we were scrolling in the opposite direction - the middle becomes the right texture, the left becomes the middle texture and the right becomes the left texture. If you think it might be a bit challenging to visualise it in your head - I agree, it took me a while before I gave up and doodled a diagram, have it:

You could argue that we could’ve easily made this work with just two instances of the texture, especially since our texture is so huge. I agree, somehow I didn’t think of it at the time and now is not the time of improving things, it’s the time of learning lessons and subduing regrets.

Miscellaneous

Let’s move on. The font that the tweets are written in is Inkburro, I’m setting it in the Utils class when I’m creating the ‘level’. It might not be very readable, but I think it adds to the whole atmosphere of deep thought and contemplation.

And then there’s music. That’s, frankly, the easiest part - I reached out to my friend Squarez and was, like: ‘Dude, I need some music’ and he was, like: ‘Here you go’. Boom, done. Check out his soundcloud page. We create a Music object, put the mp3 into it, set it to loop, set the volume to ‘not make your ears bleed’ and play it, LibGDX handles the rest. Sweet.

Can I Mess Around With The Code?

Absolutely, have a link.

Note the config.properties file, it’s where the important stuff is kept, like: number of tweets, tweets on screen, hashtag to use, your OAuth key. Enjoy.

Alternatively, you can download the jar here.