Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Saturday, February 18, 2012

Game Object Models

Right, so, continuing on from where we left off last time...

Wednesday, February 15, 2012

Object Oriented Programming

I haven't talked about programming much on here. Which makes me feel like the third word in the title of this blog is a filthy lie. To rectify this, here's some insight into something I recently discovered/learned about.

The Game Object model is a fairly straightforward model to someone with a passing familiarity of Object-Oriented Programming.

First, a primer in Object-Oriented Programming, so you, the reader, can have a passing familiarity with it, so you can see the Game Object model as being fairly straightforward.

Monday, September 12, 2011

Preliminary C++ Ranking System

AKA: C++ Belts
Students must understand/accomplish the following criteria to obtain the given ranks.

6th Kyu: IDE installed; Hello World compiled
5th Kyu: Variables, strings; functions; console I/O
4th Kyu: Arrays; loops; structs
3rd Kyu: Classes; recursive functions; pass-by-reference; using std::vectors
2nd Kyu: Inheritance; pointers; template functions
1st Kyu: Polymorphism; dynamically-allocated variables; template classes
1st Dan: Basic data structures; basic graph theory (DFS, BFS)
...

And so forth.
The basic idea is a way to quantify proficiency in programming languages, aside from an mildly arbitrary "X years of experience". That, and so I can say I have a black belt in C++.

Tuesday, August 9, 2011

Hands up, people who saw this coming

So yeah, interest in Duckbill got shot to hell. What happened? At roughly the same time, I burned myself out trying to write complicated networking code when I have only the most basic ideas of how networking works, and my artist got a real job and an internship. Yeah I had an artist working with me on that. Yeah I didn't mention that to avoid getting anybody's hopes up (not that the four of you reading this didn't already know).
Shortly after my desire to program anything hit rock-bottom, I started playing WoW.
Over a month later, here we are.

So, no games coming from me anytime in the near future.

Friday, September 10, 2010

What I've been up to

Nothing!

Okay, lies. That shmup I was making is almost nearly done. For serious. Except for the part where I need to actually make most of the content, and there's a few options I'd like to add, along with a few menus and the ability to save and etc. BUT, the big stuff is basically done.
Work on it in the future is basically horribly delayed, though, because this semester is going to be somewhat work-intensive most likely. I finally have games I need to make for class, so they should probably take priority over stuff I'd like to do instead. Also I stupidly forgot my tablet at home, and I don't want to make new graphics with just the mouse (and yes, I want more than four different types of enemy to palette-swap, and I want bosses to each be unique-ish), though I might wind up Shanghai-ing some of my artist-y friends (not too likely, sorry artist-y friends). Also it still needs a freaking title.
Rouge work will follow that, so it's something of a ways off. Which is a damn shame because my noggin is BURSTING with ideas, some of which provide interesting (horrible) problems/complexities I'd need to reconcile with each other. For example, having variable-sized enemies makes using better pathfinding algorithms trickier, though [an idea for] a solution exists.

Anyway, here have some proof that I haven't been sitting around with my thumb up my ass:

And here have one with the experimental (totally going in the final version) motion blur option:

Once again behold my not-wanting-to-crop-the-damn-image-ness.
Peace out, jerks; see you in two more months.

Thursday, July 1, 2010

Cutting work out for oneself

So, more and more recently I've been wanting to rewrite Rouge with OpenGL.
FUCK.
I just want to make it perfectly clear that I am under no illusions as to how much this is going to suck. A lot, and I mean a LOT, of things are going to need to be redone entirely. Mind you, a lot of things desperately needed redoing to begin with, so that's not even really a loss. And for the most part, the important game logic is still intact; I just need to change what's inside a few draw() functions and I'll be good to go (GROSS OVERSIMPLIFICATION AHOY).
The thing that hurts me is that a lot of (what I think are) my really cool design decisions get removed completely. Using SDLgfx to resize SDL_Surfaces gets removed in favor of just drawing a larger quad. My (terribly slow) colorMultiply function gets scrapped in favor of a glColor3f call. My hanging on to each image after it'd been processed is no longer necessary, as the processing time is now a nonissue. The hash table that ensured I only keep one processed image/color combination has no use whatsoever. The RGB function I'd made to limit the number of possible colors to keep the size of that table down is pointless and laughable.
Alas, I lay these pieces of code to rest. Let this post be their monument to existence.
Upon their headstone I lay the following benefits that this work-intensive move offers.
  • Performance will be vastly improved; memory usage will shrink to at least a third of where it stands now
  • I'll be able to more easily have several different-sized images next to each other
  • Many pieces of seemingly-redundant code will be removed; drawing routines get easier
  • The code seriously needs a good scrubbing anyway
This last point is probably the most important. I'm just going to go ahead and admit it, the code for each menu is horrible and ugly (and frankly, the menus themselves need work). Everything is done with strings, for god's sake. Example: to initialize the player's inventory, I pass a map < string, vector < pair < string, int > > > to the menu constructor, along with an ancillary vector in order to make everything the right color. This sort of thing is barbaric, insane, prone to errors (wasn't able to equip/unequip anything after changing the Item name-displaying code to use abbreviations), stupid, unwieldy, ugly, and a whole other slew of negative adjectives. Point is, it sucks and I hate it.
Where I'm going with all this: when I get back to working on Rouge, I'm not going to do anything to it for a while other than refactor existing code, improving architecture, and maybe doing some goddamn planning.
But first, I need to finish this shmup which I still don't have a title for. Deadline: end of July.

Tuesday, May 11, 2010

Somebody Save me

Saving. Hooboy.
This is gonna suck.

To save something, everything important must be written to a file. Every letter in a file takes up a byte of hard drive space.

Friday, May 7, 2010

Balance in all Things

Today I'd like to talk about my idea behind Rouge's game balance.
More specifically, how there won't be any.
Oh don't look at me like that. The game will be perfectly playable (you know, when I eventually start releasing the bloody thing), it's just that, beyond the first floor of the first dungeon, any challenge the player faces will be effectively self-imposed.
I'm basically taking the Fable approach to balance.

Thursday, March 4, 2010

Version: 0.1.2

Oh hey look, it's been a week or so.
Shutting up and coding has been rather fruitful.

So, I'm done with version 0.1.2. At least. I'd feel almost comfortable saying it was up to 0.1.5, given that these versionings are pretty much completely arbitrary and I did a good lot of stuff. Rather, did one thing very thoroughly. That said, I'm going to stick with calling it 0.1.2, but might jump up a lot after hitting some key features for 0.2

Things to do for 0.2:
  1. One infinitely-deep dungeon
  2. Enemies and items that increase in power along with dungeon level
  3. Backbone of the Skill system (the "No Useless Mages" clause)
  4. Beginning stages of enemy AI (intelligent item equipping, decent pathfinding, skill usage)
  5. Acceptably good battle mechanics (2-weapon fighting, holding one weapon in two hands, shield utility, basic combat balance)
  6. A main menu
  7. Being able to save/load

Friday, February 5, 2010

Analyze THIS

So I finally finally found a lines-of-code (LOC) counter (by which I mean, I finally looked). And the results were a little surprising.
Turns out that, overall, Rouge has roughly 2500 lines of code. Woo. So far, the biggest thing I've ever written. And yet, compared with giants like ADOM, still barely even weighing in at fetal.

Speaking of Rouge, let's talk. So around, what, three months ago was it was the last time I mentioned anything about how it's going? Yeah, around there. Yeesh.
As far as my to-do list from then goes... we'll let's just go through each item

More monsters than just goblins (trivial, enemies already loaded from data file)
Yep, it was trivial. Making those enemies interesting, on the other hand, will be significantly less so. Making them level up properly is a relatively easy thing to do, but I'm putting it off for now because other stuff is more "hey guys" in-my-face.

Menus: class choosing (on levelup, when starting a character), race choosing
Yep. Talked about it a bit a few posts back. Not too terribly done I say now (but will bemoan it within two months). I've actually spent a pretty good amount of time making the menus shinier, so the plus/minus-es stats give you are now color-coded for your convenience. And because it's pretty? Doing so in a non-head-explodey way made me improve some basic-er systems, so it'll be easier to expand upon similarly-veined stuff in the future

Enemies attack you as well (trivial)
Here's actually where my biggest issue is, the thing that's technically the easiest to do. While I COULD add the four-or-so lines of code necessary to make this work (one/two for "attack main character" and threeish for handling potentially dying), I've been not doing so because it would make the proto-game I have now completely unfun. At present, there would be exactly zero chance of surviving more than three enemies, because of how my placeholder attacking algorithm works, because there's not too much of a strength difference between a 1st level monster and a 1st level player, because there's no way to restore lost health, and because there's no items to give a player competitive advantage.


Levelup capabilities
Easily done what with the whole menu-system THING; still have to program new-class unlocking, but right now my focus is more on the item system

Respawning, dynamically generated enemies
Dynamically-generated enemies is done, haven't made 'em respawn yet. Not too terribly difficult, but not going to do it now.

So, version-wise, where are we at? Currently, I'm skirting around making the item system. It's the next major thing I need to do to make this at all playable, because as it stands now the game is a nearly-realized engine. Which is pretty much saying it's almost to the point where it's almost-a-game. So it's around v0.0.9. When I put some basic items in, like a basic sword and piece of armor, then I'll turn on enemies attacking, and then I'll call it v0.1.
And maybe then I'll post some fucking screenshots or something.

Wednesday, February 3, 2010

And Now for something Completely Different

So I've been working on a side-project in pygame for a while now. Probably long enough to constitute more than a side project per se, but whatever. Not gonna explain anything about it, but here's a few things I made it do that made me smile.
  • Implemented my very own Vector class. Not the vector that means "a smarter array", that'd be stupid (python, remember?). No, my Vector class is pretty much the backbone of the nifty-ish things I can make the game do, and best yet it integrates quite well with the tuples that pygame assumes I'm using anyway, so for system calls to drawing functions, for instance, I don't even need to convert my Vectors into tuples (because for all intents and purposes as called by a function, they behave pretty much identically).
  • Finally got bullet motion pretty much ironed out. Bullets spread out in a gaussian distribution, so shotguns are worthwhile at medium range. Collision detection is implemented in a way such that bullets "move" ten pixels at a time (currently enemies are 40x40 rectangles) so as to ensure hitting enemies even when moving at high velocity. Still to do: implement a recoil system where your rapid-fire guns are more accurate when fired in short bursts.
  • It's got explosions in it. Explosions are drawn to any arbitrary size based on the radius of said explosion. To draw an explosion, I draw circles on top of one another of varying color, starting with orange on the rim, passing through yellow in the middle, nearing white at the center. In order to keep from having to re-render each explosion each time it's called, I first check if the explosion is already stored in a list I've made. If so, I just draw the pre-rendered image. If not, I make the image, then draw it. This technique I learned while working on Rouge (which I will do more of eventually).
And for another aside: Mass Effect 2 is completely fantastic. I'll review it once I stop being too excited about it and can analyze it fairly.

Monday, January 25, 2010

The Menu for this evening

I've spent a good deal of time re-tweaking the menu systems.
One thing I've never been fond of in roguelikes is looking at a list of choices where half the things make me ask "what the hell is that?" And even if I know what something is, that doesn't mean I know enough to make good decisions about it. I can surmise that a Troll has higher Strength and lower Intelligence, making one a poor choice for a Mage character, but I can't intuit that trolls have slightly better-than-average Willpower scores, making them more resistant to magic, and I'm not certain whether this universe has the "trolls heal quickly" rule in play.
And while I could easily just tell players to RTFM (I mean, it is a roguelike...), there's no reason to assume everyone has prescient knowledge of the design decisions I've made to differentiate my world from the "standard fantasy setting" a.k.a. Tolkien (Our Elves are Better, after all).
So, I added a bit where you can see a description of what you're picking. Right now I've just got the stat plus/minus-es, but in the future that'll come alongside some flavor text for each thing. In order to actually see the description, I've added a cursor, letting you select which thing you want to look at. You can still just strike the key corresponding to the thing desired, for those who know what stuff is and just want to get on with it without having to scroll the bloody thing down. And you can jump the cursor directly to what you want to look at by holding Alt and pressing the corresponding key (which honestly feels a bit awkward. I'll probably change it to Ctrl, which involves changing a single character in the code thanks to my sexy, sexy Input class).

Programmatically, the coolest thing about the menu system is that it's almost completely modular. I used to have each MenuState class handle redundant things like making the list of stuff to show, handling inputs (from the Input class, of course), etc. Now all the generic stuff is put in the Menu class, and each MenuState has a Menu as part of it. Each MenuState now only has code relevant to the different things it does, which is the whole bloody point of classes in the first place.

Friday, January 22, 2010

Rumors of my Death would've been Greatly Exaggerated, but everyone knew I was alive

There's a metaphorical saddle that I'm presumably "back in" right now.
Here's a brief overview of programming-related Things pertinent to me at the moment:
  • The amount of progress I had made on Rouge since my last post right up until yesterday has been precisely nothing. The past 24hours have been focused on transporting the files from a Visual Studio project in Vista to a Code::Blocks project in Fedora 12.
  • It is remarkably easier to program things in Linux.
  • Python is fantastically cool, and will probably be what I use to do a good chunk of other projects. I'm not rewriting Rouge in Python though, god no.

Sunday, November 15, 2009

Okay I'm a Liar

Okay, so on reflection, I may have made a few misstatements last time.
Firstofall, the games is probably around v0.0.7 now; I forgot about making a menu system to initialize your character and level up and things. And implementing the menu system nudged me forth into finally rewriting the input system (more on that shortly).
Secondly, "Mechanics derived more from jRPGs" is probably a staight-out lie. Or at least a half-truth. Thing is, I am straight up tired of people just cribbing mechanics right from the d20 system and calling that their gameplay. So, a more accurate statement would have been: "Mechanics made up by me". I suppose this might constitute as throwing down a gauntlet, but for a genre consistently described as being the pinnacle of "gameplay over graphics", the mechanics tend toward similarity more often than not.

So, the new input system. Long story short, instead of each game state having to take into account keypresses, there's now an overarching input system that translates input into a string. Instead of having to say if(event.key.keysym.sym == SDLK_LEFT), I can now just say if(input == "left"). If shift is held down, it either capitalizes the letter where appropriate, or adds S to the front of it. If ctrl is down, C gets added to the front. If alt, M (for meta. Yes it makes perfect sense, just go with it). This simplifies things greatly when it comes to compund inputs. It also makes accessing items off a menus much, much easier programmatically. Instead of having to convert keypress inputs into an integer, then access the data at the right location, I can just iterate over the array and match the input letter with the item letter. It also makes editing the config files (which I will program sooner or later) much easier, as well as greatly simplifying the code for the "Help->Keybindings" command.

And now, in lieu of more content, screenshot time!

Human Warrior fights Goblins


Elven Mage faces off with a Goblin


Halfling Thief appreciates the randomly-generated level

The stats pane is deprecated. I'm probably going to put it on the bottom of the screen. And it isn't going to have every stat on it, but the more important derived stats (HP, MP, ATK, DEF), and XP  out of ToNextLevel (TNL). There will be a separate, more detailed stats page with a full report.
Finally, a list of things to implement before I consider the game v0.1
  • More monsters than just goblins (trivial, enemies already loaded from data file)
  • Menus: class choosing (on levelup, when starting a character), race choosing
  • Enemies attack you as well (trivial)
  • Levelup capabilities
  • Respawning, dynamically generated enemies
For v0.2, I'm looking to have classes unlockable as you level, a multi-level dungeon, and the save system, among other things. Yes, this is getting ahead of myself.

Wednesday, October 21, 2009

Vision - II

More adventures with keeping track of where things are.

Redid LOS algorithm with doubles instead of ints, which doesn't actually affect much of anything, other than where I do my casting to make the compiler stop warning me about it. Ah well, it only took five minutes.

My other hilarious problem came about when I got into circular definition funtimes.
I want the Character class to be aware of the Map class, so it can have a pointer to the Map it's on, so it can get Tiles on the Map as part of its visibility subroutine. Fine, I declare Characters after Tiles.
I want the Tile class to be aware of the Character class so it can have a pointer to the Character standing on the Tile, so it can tell Characters wanting to move onto the Tile whether the position is occupied or otherwise. Doable, just declare the existence of the Character class before implementing the class; as long as I only need pointers to it, it works out okay.
I also want to draw the single topmost object on the Tile, in the order of Character, Item, floor. This lets me cut down on managing drawing the player, drawing the tile, drawing enemies if they're in sight etc. and just draw what's on any given tile. This also keeps me from drawing several tiles over another, which is ugly because the non-colored space on each letter is transparent, so you can see the floor through the player. (Why not leave the black background on each Image and just draw Tiles then Items then Characters? Because then the 3D engine would look odd, silly)
PROBLEM: the draw() routine for the Character class has yet to be defined, seeing as we've yet to implement it, having only declared its existence. Can't I just declare the Character class before the Tile class? No, because then I'd run into similar issues within Character's implementation, only many more times over, seeing as how heavily several functions in Character rely on the Map class, which has a 2D array (vector) of Tiles, and Map also uses Tiles' functions. [From here on out, when I say array, assume I mean vector. I don't explicity say vector because of the Math and Physics associations they have, and I rather like those things too]
So, not too horrible, as it's only one function, and it's a function that most of the classes so far have, along with a member of the Image class (which holds several SDL_Surface*s and deals with scaling and recoloring them, very handy). So I figure, I can inherit both of those from a new base class that just has an Image and a basic draw() routine, and use virtual functions to handle the Images differently depending on the class. Turns out that you can't declare a class's base class without also implementing the class; so I was back where I started. Then an ingenious idea hit, use polymorphism. This would've been fantastic, if Visual Studio didn't forget how to use virtual functions for no apparent reason (either that or I'm doing it wrong but no I'm not shutup), and the base class pointer to a character didn't only use the base class draw function.
So, in an act of spaghettification that I wasn't particularly looking forward to, I declared the Tile::draw() function and then implemented it after the Character implementation. In the separate character.h file. Oh goody.

On further reflection (i.e., typing this entry, a.k.a. the entire reason I'm writing this down in the first place), the polymorphic approach should work, and I can't think of why it doesn't. Trying it again - I first re-read my references and run the debugger at the point at which I call the polymorphic draw() - I try making the base class' virtual draw() a fully virtual function, so it doesn't ever to execute. Turns out that it uses the base draw, even though the Character class redefines draw and has a virtual pointer to it, because the redefinition takes place after the point at which the base->draw() call occurs. So in short, it's an extension of trying to use Characters' draw function without declaring it, only without the compiler errors.
Has no one else needed to do something like this? Oh well, back to the spaghetti. On the plus side, ugly code is better than code that doesn't work, so at least I've got that going for me...

So what did all that have to do with vision?
Not altogether too much, but it does let me do some cool things. For starters, differentiating between visible or out-of-sight tiles is doable without needing to store visibility data on the tiles themselves, which would be useless data most of the time, given the probably small percentage of tiles on a given Map that would be visible at any given time. Secondly, it removes the need to keep track of what has been drawn on what tiles already; it's implicitly assumed that each tile is only drawn once (and would draw the same thing each time it's drawn). Thirdly, keeping track of which enemy is on a given tile greatly simplifies finding which enemy you just attacked, or which ally you just healed, etc.

Tuesday, October 20, 2009

Vision - I

Finally got a Line of Sight (LOS) algorithm implemented.

My first quick-and-dirty "ingenious" idea that struck at around 11:00 at night (PROTIP: you should never code when you're tired, even though I'm going to break this tip (again) as soon as this post is done) was to use a filling algorithm in the vein of breadth-first-search, i.e. starting from the tile the Character is on, giving each tile considered a value of the current tile's value+1 and pushing on a priority queue until the current value was greater than the player's LOS distance. Then I realized that I'd need to increase the value by sqrt(2) for diagonal values, unless I wanted the player to be able to see in a square.
It wasn't until AFTER I'd finished coding it that I realized that this would let the player's sight "spill" around walls. By this point, it was nearly midnight, and 8am class was beginning to rear its ugly head at me from the future, so I put my code, my computer, myself to sleep.

My next idea (a.k.a the right way how to do it) was to get a series of points in a circle around the player at a distance R, then draw lines from the player to those points, stopping if a wall interuppted a line. Take all the points a line went through and store them in an array (STL vector, naturally) associated with a Character. Thus we have all the Tiles that any given Character can see, and from there we can either show the player visible tiles, or see if an enemy can see the player.

As an aside, I'm wondering if there's a better way to show the duller tiles that are out of the active visibility field than storing a second surface for each image color multiplying by a down-factor (20% darker?), or storing a second surface at a slightly smaller size. For now I'm going to implement the second image with a color multiply, but I'm thinking out loud here. And scowling to myself, knowing "there's gotta be a better way".

On LOS: my first instinct was to repurpose code I'd written earlier for a different project that would draw lines circles with pixels, changing the "putPixel" faux-routines I'd written into adding Tiles to a vector and returning it (I didn't have a putPixel function written, but that was thanks to the horrendous overhead of the thousands of function calls it wound up making; something the inline command failed to help with at all). This, of course, led to several issues.
Firstly, the lines would start inside of walls sometimes, and not draw in certain directions others, but only in some positions. Quickly, I realized it was because the particular implementation of the Bresenham algorithm I was using didn't necessarily draw lines from the point 1 to point 2, so I had to rework it a bit so it would work without swapping the points.
Still, though, the visible field it gave me was completely off. The line-drawing algorithm worked perfectly sometimes, so that probably wasn't it. It turned out to be that in my reimplementation of the circle-drawing algorithm, I hadn't referred to the code that actually produced a working circle, but instead some notes on circle geometry that hadn't worked out so well at all (but looked convincing on paper). How I was doing it was dividing the circle into 1-tile-high slices from j = y - R to j = y + R and using the points on the left and right edges of each slice. The problem was, I was taking the width of each slice as w = 2*R*sin(acos((R-j)/R)) which anyone can see will cause problems. For those who actually care, the correct width was 2*sqrt(R^2-(R-j)^2).
That worked much better, and gave me a contained field in the shape of a circle that the player could see and moved consistently with the player. All well and good, but it had several holes in it near the y-axis for no apparent reason. Then it clicked that while the slice-based algorithm worked acceptably well for drawing full circles with rectangles, it only considered one point per horizontal line, which left noticable gaps near the top parts of the circle, where the slope of the tangent was much flatter.
So I buckled down and looked up the "Bresenham" circle-drawing algorithm (not actually designed by Bresenham, but similar enough to his line-drawing algorithm that people give him credit for it). The version that I shamelessly stole off Wikipedia is fairly inelegant to my eyes (I much prefer minimizing lines of code; ironic then that I'm writing a roguelike), but I so far cannot be bothered cleaning it up with for loops instead of eight explicit putpixel functions (on reflection, an idea for which has just struck; it also involves bitwise operations, which are pretty as far as I'm concerned). For LOC, it works significantly better, and gives a mostly-full circle (dropping, amusingly, only the 45-degree angles).

Now I'm off to improve it using floating-point values for x,y offsets of the points on the circle, which I'd put off until now because I'd been reimplementing the way Tiles displayed themselves and their contents. I.e., I finally started giving Tiles contents.