Dungeon Crawler Dev Diary

Make games! Discuss those games here.

Moderators: Bob the Hamster, marionline, SDHawk

User avatar
Mogri
Super Slime
Posts: 4669
Joined: Mon Oct 15, 2007 6:38 pm
Location: Austin, TX
Contact:

Post by Mogri »

We're handling input

You might recall this from two posts ago:

Code: Select all

while(true) { 
    handlePlayerInput() 
    updateGameState() 
    renderGraphics() 
}
The problem with input handling is that buttons don't always do the same thing. If I push the B button, it might mean I want to run, or it might mean that I want to leave the menu I'm in. The input handling is dependent on the context. (This isn't a huge problem in OHRRPGCE games, where we can just pause script execution while the engine deals with input handling on menus.)

In some games, we can tightly couple the player input with the game state, so that it looks more like this:

Code: Select all

while(true) { 
    handlePlayerInputAndUpdateGameState() 
    renderGraphics() 
}
There are two ways to check for input in libGDX:

Code: Select all

boolean isAPressed = Gdx.input.isKeyPressed(Keys.A);
This is polling. You can do it from anywhere, which is handy.

Code: Select all

public class MyInputProcessor implements InputProcessor {
   public boolean keyDown (int keycode) {
      // your code here
   }
   public boolean keyUp (int keycode) {
      // your code here
   }
   ...
This is the InputProcessor listener. You can't put the keyDown function just anywhere; it has to be in one of these specific listener classes. Also, you have to tell Gdx which input processor(s) it should be using at any given time.

Now, you might look at this and think, "It looks like polling has less overhead and more flexibility. Why would you ever use InputProcessor?" This mostly boils down to InputProcessor handling more events. Polling lets us check if a key is pressed, which is great. It also offers isKeyJustPressed, which tells us if a key is newly pressed. It does not tell us when a key is released, though, and InputProcessor does. InputProcessor also gives better exposure to mouse events such as the scroll wheel.

Like the above title suggests, the game now accepts keyboard input: you can wander around the demo map. This is great news, and at this pace, the game will be done in approximately 20 years.

Ha! I am only half serious. But in other news, I realized as I was doing this that I need to adjust the camera. I had it set back by half a tile, which looked nice until you turned 90 degrees, at which point it was apparent that you were between tiles.

I tried moving the camera all the way back up, which fixes the issue of being between tiles, but now it looks like you have your nose smooshed up against the wall when you're right next to it. The fix here was to have the camera "float" behind the player's current position, similar to how it was before, but adjusting when the player rotates.
User avatar
Mogri
Super Slime
Posts: 4669
Joined: Mon Oct 15, 2007 6:38 pm
Location: Austin, TX
Contact:

Post by Mogri »

Class Spotlight: The Wizard

This is a really good time to point out that all of this game design information is tentative and subject to change, especially given that I haven't even begun to balance the classes. THAT SAID

In a recent change that I might regret (but probably not?), I've decided that all classes will be able to use all spells and equipment. I'm still undecided on the priest's godly petitions, but I'm leaning towards yes on that also.

"Hold on," you say. "What's the point of having a class system, then? Especially what's the point of a wizard class if it can't cast anything no one else can?"

Good question. Let's start by looking at one of the first abilities the wizard can learn:
Staff Proficiency: Staff CP costs are halved, and magic costs are reduced by 1 MP when wielding a staff.
For each class of equipment, there's a Proficiency skill that halves the cost of evoking that kind of equipment as well as conferring a side benefit. In the case of staves, that means cheaper magic. A wizard with Staff Proficiency won't cast spells more powerfully than anyone else with the same stats, but he will be able to cast more often, especially since he can evoke the staff to use its spell using renewable CP instead of MP.

Later, wizards gain access to Double Magic and Triple Magic, which allow them to cast a spell two or three times in a single round at the cost of additional MP. This makes wizards the best burst damage dealers in the game.

We'll look at subclassing combos when we examine other classes in detail.
User avatar
Mogri
Super Slime
Posts: 4669
Joined: Mon Oct 15, 2007 6:38 pm
Location: Austin, TX
Contact:

Post by Mogri »

How about some screenshots already

Yeah, that's fair. I mean, I've been working on a lot of stuff you can't see, but there's of course been major improvements since the last screenshot.

Image

First off, and most obviously, I added floor and ceiling. They're really ugly next to the wall tiles, but these are all placeholder graphics anyway. Please don't take this as indicative of the final product in any way, shape, or form.

Secondly, the walls now have depth instead of looking like pieces of paper. You can see where the walls intersect that they join up at the corner. I will probably add some beveling to make it look more corner-ish. I rewrote the wall generation basically from scratch to get this to work, and it was way more trouble than it should have been. Thanks, 3D.

Third, the lighting is much better, since I am lighting based on the player position rather than using fixed directional lighting. There's still room for improvement here, and this is where you might well argue that I have gone down the rabbit hole: I might just write my own shader.

"But what," you ask, "is a shader?"

Good question. Shaders do the heavy math involved in telling the CPU how to turn numbers into colors. In libGDX, shaders are written in GLSL (OpenGL Shader Language), which is a lot like C. The advantage here is that GLSL is very low-level, allowing you to access the graphics pipeline more directly and with lower overhead.

(And yes. They are basically written in C in Java. It is a bit silly, but it sure beats doing the whole project in C.)

Now, your next question might easily be, "Why bother writing a new shader? The one you're using seems perfectly capable." And yes, that's certainly true, and if I were planning on doing 3D modeling instead of textures, it would be perfect. But as it stands, we've more or less reached the limit of what it has to offer. To get better lighting with 2D textures at this point, we need to turn to normal maps.

"But what," you ask, "is a normal map?"

Uh, okay. Here we need to assume that you know a little bit about 3D geometry (but not much, and if you're good with 2D geometry, you should be fine here).

When we create a 2D shape in 3D space, we can imagine it as part of a plane. That entire plane has a vector that's orthogonal to it (well, two if you consider the front and back to be separate). "Orthogonal" is more or less the 3D form of "perpendicular." If you look at the floor as a plane, then straight up and straight down are orthogonal to it. For 3D, we care about the orthogonal, or normal, vector because it tells us which way a surface is facing.

And it's from that same term that we get "normal map." Normal maps are funky-looking images that convey information about the length of the normal vector -- or, in other words, we can overlay a normal map onto a texture to tell the shader to treat the surface like it has some depth to it. Why does that matter?

Image

Because if the surface has depth, then we can cast dynamic light on it. Now we're cooking with gas. With a little luck, the dungeon will be looking more like the picture on the right next week. (But it will probably still be placeholder graphics.)
User avatar
Mogri
Super Slime
Posts: 4669
Joined: Mon Oct 15, 2007 6:38 pm
Location: Austin, TX
Contact:

Post by Mogri »

GLSL Shaders
A Play in 12 Acts

HOUR 1

Hey, this isn't so bad. I can read and understand GLSL code, and I have example code. This might be no problem after all!

HOUR 2

Oh, hmm. They might be using a different version or something. I don't know where these variables are coming from.

HOUR 4

Hold on a second. This tutorial is for 2D! That's no good! *cue furious Googling*

HOUR 6

OK, I have a 3D example to work from... with even more variables I can't make heads or tails of. Who in the world uses single-letter variable names?

HOUR 7

I really wish I had paid more attention in my linear algebra class. I can't remember the difference between a cross-product and a dot-product, and I really don't want to figure it out right now.

HOUR 8

Why is the eye vector always zero? Why is the light vector constant, too, for that matter?

HOUR 9

Oh! Those single-letter variables are normal, binormal, and tangent. I don't know what those mean, but I can figure it out.

HOUR 10

Hey! Fixing the tangent fixed the vectors. Maybe now, the fragment shader will start working.

HOUR 10.2

Well, it's doing something, but it's pretty ugly.

HOUR 10.5

Oh, no wonder. These numbers are all wrong.

HOUR 11

*furious number-tweaking*

HOUR 12

It's aliiiiiiive

BEFORE:
Image

AFTER:
Image

(I think the light source is too yellow in these screens, but it's too yellow in both of them, so that doesn't really affect the side-by-side comparison.)

It's hard to convey how much nicer this looks in stills, but when it's in motion, man does it look good. I almost worry that I've entered the graphical uncanny valley: if the walls start looking too good, their boxy shape will look worse by comparison.

How hard was this to write? Honestly, much easier than I expected. The terminology surrounding all of this is so incredibly dense that I could easily spend months breaking down exactly what's going on in this code. I did have to dig into it enough to figure out at a high level what it's doing, but the equations are the kind of thing people write dissertations about. So it's a good thing the math is well-understood by other people, and I'm grateful for their work.

I think I'm ready to call this part of the engine good enough for now. Next up: the abyss that is UI. Menus and text boxes, hooray!
User avatar
Taco Bot
Meat, Cheese, and Silicon
Posts: 484
Joined: Fri Jul 18, 2014 12:15 am
Location: Santa Cruz
Contact:

Post by Taco Bot »

Haha, sorry that it was such an ordeal. The normal mapping looks awesome though!
Sent from my iPhone
User avatar
Mogri
Super Slime
Posts: 4669
Joined: Mon Oct 15, 2007 6:38 pm
Location: Austin, TX
Contact:

Post by Mogri »

Oh, I should add that I found a fantastic utility to create normal maps from images. Check out CrazyBump if you ever find you have a need for this.
User avatar
Mogri
Super Slime
Posts: 4669
Joined: Mon Oct 15, 2007 6:38 pm
Location: Austin, TX
Contact:

Post by Mogri »

Why Mod?

I've mentioned modding support previously. You might ask yourself, "Isn't that a lot of overhead? Why bother?" That is a good question, and there are lots of good answers. Let's look at a few of them.

Longevity

When a modding community springs up around a game, the game gets a new lease on life. Games like Neverwinter Nights enjoy many more years of popularity than they would if they released with just the campaign.

This has tremendous implications for games that rely on the long tail revenue model, especially when modding support includes the ability to add new localizations and therefore open new markets for your game long after its initial release.

To look at it from another angle, the OHRRPGCE is essentially Wandering Hamster with modding support, which gave an unfinished game a 20-year following (and counting). It helps that it's free, but the same principles apply.

Tooling

I said earlier that I didn't plan to create a map editor, but I might change my mind on that. In the long run, it will probably save me time. The same is true for other tools, and if I make them, there's no reason not to make them available for modders.

This might seem like circular reasoning -- "mod support is good because it gives you a reason to make mod support tools" -- but the real advantage here is that it gives you a reason to make proper dev tools, which are otherwise easy to neglect. And that's important, because...

Convenience

Once the game engine is patched together, most of the remaining work is putting together the game data. The easier that is to do, the better your life as a developer is going to be. As an analogy, imagine if the OHRRPGCE didn't have CUSTOM.EXE. It's possible to make your game by assembling the files by hand, but it's way harder!

On the other side of the convenience coin, the less of the game that lives inside the engine, the better off you're going to be. Every change to the code requires you to recompile. Today, I can do that in less than a second, but when the code base gets bigger, that might mean waiting 15 minutes every time I want to tweak how an ability works. And if you're going to have the bulk of the game live in the data...

Might as well

At that point, there's no reason not to make the game moddable. Then, you can sit back and watch as your players do your job for you.



I'm on vacation next week, so I won't be writing then, and this might be my only article for this week. In the meantime, I am happy to take topic requests!
Post Reply