Advertisement Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    122
  • comments
    121
  • views
    68965

About this blog

My not-so daily posts on my current console project

Entries in this blog

 

Cripes! on indeterminate-length hold

I had to send my laptop in for repair recently, not to mention - if you haven't noticed - development has ground to a halt anyways. If and when I get back to Cripes!, I'll be doing an overhaul of the design, anyways.

My latest project is - of course - a MUD. How obvious... Well, I may as well post a bit of what's going on with that.


ExplorerMUD ((yes, that's what it's called >_>))

I'm going to try to work with a modular, object-oriented design. At the moment all I've got running is a basic listening server which creates a new thread for each client, sends "Hello World!" to the client, and disconnects. That's probably a good thing, because I left it on once when I went to school, and I had a connection from some person in Peru when I got back... what the?

Before I go on, I realized something about access specifiers and inheritance, which actually is very interesting and useful, although probably somewhat obvious if you think about it... a class with private and public members can be instantiated, and it works like you'd think, right? I don't really need (or want) to explain that. If you derive from that class, the public members remain usable within and outside the derived class, and the private members can't be used directly in either. But if the inherited public members access the private members, they still can! Like I said, it's obvious, but not really - in my case at least - something you'd think about most of the time.

This is one of those things where you have a - ha ha - paradigm shift. I've always thought (yes, I'm stupid), "what's the point of deriving from a class with private fields? If you can't use those it breaks the class." Well see, this is why it's useful to do that. It's another layer of encapsulation.

So, I've created a Thread class which can be used a bit like a Java thread: you just derive from it, and implement a Main() function. There's some encapsulated Thread info, like the thread ID, inside the base Thread class, but it's private so not even its derived classes can access it. But it defines protected and public members so they can be reached in some manner or other. There's a Start() function defined in Thread, for example, that starts a new thread as well as storing internal data about the thread. It starts the thread under a private member, Go(), which essentially encapsulates some ugly thread-specific calls and allows the virtual Main() to use the return keyword instead of, say, pthread_exit().

When you derive a Thread, you can create fields and functions within it, of course. Mutexes are a good example, as are functions that notify the thread in some manner that there's something to be done. The Thread class derivatives can allow for an inter-thread interface this way. You can also add fields to emulate arguments to Main() - pthread_create only accepts void functions accepting a void pointer, so for simplicity I do it this way - and create a constructor to fill those fields in before Create()ion.

That was long... >_>


I'll, um, save my speech on getting input from stdin via select() for later. Suffice to say, you can't use cin.

I'm doing all of this on Ubuntu, if you're wondering.
~Jonathan

Twisol

Twisol

 

Cripes! and birthdays

Alright, so, you may have noticed the conspicuous lack of updates here. The main reason for this is that I've been on quite the series of vacations, and I just haven't been able to take the time to sit down and code. The laptop I normally take on trips, well, somehow the left side of the lid broke at the hinge area. The hinge itself didn't break, but the left side of the monitor casing did, so.. when I try to close the laptop up, the seam pops, and it makes all kinds of nasty noises that I don't like. I try to avoid closing it, which means avoiding... packing... it. I need to get it fixed, but hey - I've been on vacation!

Also, the 11th is my 16th birthday. While we were in Florida (which I just got back from, like, two hours ago!), I was talking with my cousins, and I decided that "Sweet 16" just wouldn't work for me. We came up with a lot of funny, and of course stupid, words to put before 16. "Sexy" inevitably came up, and even I think I'm pretty good-looking, I'm not so sure about sexy. I had to pass on that one. Anyways, happy birthday to me! Blizzcon tickets are going on sale that day, ironically, and I want to go. Last year I went for my birthday... this year it looks like I'm getting tickets for my birthday. Woohoo.

Oh yeaaah... I'm in the Wrath of the Lich King beta, did I mention?

Twisol

Twisol

 

Screenie

So far, this is what I have on Creditor. The menu's going nicely, as you can see, and whenever the mouse is placed over a menu item, the HandleMouseEvent function knows and changes the color of whatever is underneath it. Unfortunately it doesn't know what color it was before, so I had to hardcode the colors it changes between for now. Nonetheless, I think it's going pretty well so far!



The coordinate you see on the right is just there for debugging, it shows where the mouse is pointing at that moment. You can't tell, but the mouse is pointing at the 'd' in "Edit" in the picture.

Twisol

Twisol

 

HUD changes

To make way for some functionality I'm implementing in the map editor (I think I'll call it Creditor), I had to go, ah, "under the HUD" to change a few details. One notable change is that the statinfo class stores a pointer to an "IStringable" interface, which defines an abstract ToString() function. This didn't require as much code change as I thought it would, which is good. I derived a Stat template class which defines its ToString() method as lexical_cast'ing the stat and returning the result. If lexical_cast throws an exception, I return a blank string instead.

The root reasons for doing this is because (1) someone on IRC told me it was pretty limiting to only be able to use integers, and (2) because I wanted to be able to have my menu options as actual words, and be able to change their color or whatnot at the same time (DrawStatic is pretttty clunky for that).

I also made some fixes to some silly errors I made in the original HUD implementation. I had a cctor and an op=, but I was only copying the value of the buffer pointer over. They basically pointed to the same buffer after the operation. That's not good, especially because that would mean the two objects' destructors would delete the same memory twice. Idiot.

Twisol

Twisol

 

USC, SAT, WTF OMG BBQ!

My family and I did a Meet USC program yesterday. USC is the University of Southern California, and their Meet USC program is basically a three-hour tour, where the last hour includes talking with the admissions person at a specific school within the university. A little backstory before I go further:

For the longest time, I've wanted to go to Digipen. Sure, no problem, right? Well, a few weeks ago I stumbled across an article on Josh Petrie's blog - yes, that jpetrie - that weighed trade schools like Digipen against traditional universities. A whole lot of what he said made sense to me, and he had even gone to Digipen himself. So going along with the article, I decided to see what my options were.

Ironically - or perhaps poetically just? - the first university I saw was USC. I read up on it and it really looked like just what I wanted. I even managed to talk with an alumnus - on #gamedev no less! - and got his opinion on it. Better, they have a Computer Science degree with an emphasis on Games. It's still a CS degree, meaning I'm not really going for one of those game development degrees so many people have told me to stay away from... like Digipen's. Now, that is irony.

Fast forward to yesterday's Meet USC tour (which I signed up for about a week or so beforehand). It started with a presentation by two peple, one who was going to be a senior next semester and was double majoring, did overseas study, et cetera. The other was an admissions person for the university. They said some stuff about USC, went over applications, and other stuff. Did you know they have over 600 clubs at USC? Yeah. One of them was founded by Will Ferrel while he was there; it's called the Lizard Lovers. The admissions person also told us - oh, did I mention, we weren't the only ones at the Meet USC tour? :P - about an applicant who, when answering an "Explain yourself in three words" question, wrote "A sexy beast".

For the second hour we walked around the campus with a goofy, but nice and informative tour guide. Not much I remember about that hour, although that's when I learned the bit about Will Ferrel's club.

During the third hour, the group got split up according to the studies they wanted to do. We went with the Architecture and Engineering group because the Viterbi School of Engineering is the one that runs the Computer Science (Games) program. A guy who worked there sat down with us (only four of the original group were interested in Engineering) and talked with us about how things would work relevant to the Engineering classes. A lot of good information all around, but by then I was getting hungry. ;P

I absolutely enjoyed the Meet USC tour, and I've definitely decided that this is the university I want to go to. Yaay. :D

Now on to the next acronym. I have to take my SAT and some SAT Subject tests in order to apply. I already downloaded and did some of the SAT Practice Test, but I'm not sure I'm absolutely prepared for the actual test. But I have until October before the next SAT will be held, which is good. I bought an SAT study book from those Kaplan study book people today, and I'm having it shipped in 3-4 business days, so it should be here relatively soon.


Now, after my rambling about college and testing, I'm sure you want to hear more about Cripes. Right? Right? No? Too bad. I've made some changes to how I catch and handle input events, so I can handle mouse and keyboard events simultaneously. It's slightly reminiscient of the typical windows message loop with GetMessage/PeekMessage, which is, in my opinion, a Good Thing.

I'm also slightly surprised at how easy it was to set up simple HUD and GameView windows in the console, but that's kind of the point, anyways. I'll be using the HUD to display the characters and colors you can click to select. I might even make a small menubar at the top to easily load and save maps, and other things like that.


Alright, have fun reading all of that. And as always, comment nao!!

Twisol

Twisol

 

Slight setback, back on track

I had some annoying little problems that I, being the perfectionist that I am, had to solve before moving on to the map editor. Oops.

The inner class I mentioned was fun and interesting, and certainly a good idea in some cases, after I made some improvements I realized I didn't actually need it anymore. I moved its methods back into the GameView and it works fine again.

I also hit a small roadblock while tinkering with my Entity class, and deriving from it to allow for collision detection. (Somehow, I always get sidetracked...) Apparently, if your base class has a function overloaded at least twice, and your derived class only implements one of those, you can't call the other. You actually have to name the 'other' overload something else, basically meaning it isn't an overload any more. It feels really, really stupid. This relates to my Entity by way of the entity's position. I was going to derive Entity and add Move() functions that would only move if it didn't collide with anything, but then I realized that the position COORD would still be directly modifiable, allowing for a way around the collision detection. This isn't necessarily a bad thing, but on the other hand if you wanted to make an entity that went through walls sometimes, you could add a boolean "isGhosting" to your derived and do it based on that, still by using Move().

In short, I cut out the setter-Position() functions from the base Entity class, because Entity doesn't really need them; it's basically just an interface that provides the functionality GameView needs. And GameView doesn't need to change the position, only find out what it is for drawing - the user of the Entity is in charge of movement.


That said, the Entity isn't necessarily bound to the GameView. You could quite easily use it yourself without the GameView at all. However, in my case, when deriving from the Entity, I gave my new Body class a GameView pointer, so it can access the map layout of the GameView for collision detection. That's really at the user's discretion though (via deriving), so I wouldn't say that the Entity is coupled with the GameView.

Now, don't let me do anything else with Cripes before I finish the map editor! Sheesh :(

Twisol

Twisol

 

Inner classes and map editing

I've decided I want to work on my map system first, heh. I decided to try something new to prepare for it, and I created my first inner class in my GameView. The definition of the 'mapaccessor' is private, but I declare a public instance called 'map'. Its only role in life is to provide a clear method of accessing the GameView's map buffer. For example:


// gameview with a map of size (5, 5) and a window of the same size
GameView gv(5, 5, 5, 5);

// read and print the character at (0, 0)
cout
// change the color at (0, 0) to green
// the CC_* enum is defined in another header I made, "conutil.h"
gv.map[0].Attributes = CC_GREEN;


The mapaccessor inner class is defined as:


class mapaccessor
{
private:
GameView& rGv;
public:
mapaccessor(GameView* gv)
: rGv(*gv)
{}

CHAR_INFO& operator[] (int idx)
{
if (idx > rGv.realsize.X * rGv.realsize.Y)
throw std::out_of_range("Attempt to index out of array bounds.");
else
return rGv.playbuf[idx];
}
};


I'll be adding an operator= as well, which takes a CHAR_INFO*, mainly for loading an entire map buffer.

Do you see how my mapaccessor takes a GameView pointer? The GameView which instantiates a mapaccessor passes 'this' to the mapaccessor constructor, which stores the address in a GameView reference. Now, in general it's not a good idea to pass 'this' to another ctor, especially in the initializer list. If the code you called happens to access a member of *this that hasn't been initialized yet, bad things happen. The reason I can get away with this is because I only ever store the value of 'this' itself, namely the address of the new object.

I could certainly have just overloaded operator[] on the GameView, true. However, it's not quite as clear what you're accessing just from glancing at the code. Moreover, if I were to implement an operator= on the GameView, in the manner I explained two paragraphs ago, that would be even stranger if you don't know what's going on to begin with. Using the mapaccessor gives code the syntax and clarity of accessing a public array member, but the safety (array bounds checking) and ease of use (such as operator=) of a private member with get/set functions. Handy, no?

Once I have operator= implemented, I think I'll try a simple map editor. It's going to use the GameView, just like the game itself - in fact, what you see in the map editor will be exactly what you see and how you see it in the game - but with a "tablet" of all of the ASCII characters that you can click to select. Yes, you'll be able to use the mouse in the editor. That should make things a bit simpler!

Oh, and a big thanks to ibutsu at #gamedev for the C++ FAQ Lite link on using 'this' in a constructor.


~Jonathan

Twisol

Twisol

 

Entity drawing!

I finally finished my entity-drawing algorithm! It was a huge pain, but I'm pretty happy with what I have now. The first version that actually worked was pretty clunky, with something like seven for-loops -- one for each entity, two for each sprite character coord, two for each possible looped-around drawing coord, and three consecutive loops to add the "good" X and Y values to vectors and draw them. This version is considerably condensed, heh. Only five for-loops...


COORD loopedtimes = {(viewloc.X+viewsize.X-1)/realsize.X, (viewloc.Y+viewsize.Y-1)/realsize.Y};

for (std::list::iterator itr = entities.begin(); itr != entities.end(); ++itr)
{
entity* ent = *itr;

for (int Y = 0; Y Size().Y; ++Y)
{
for (int X = 0; X Size().X; ++X)
{
for (int j = 0; j {
for (int i = 0; i {
COORD point = {ent->position.X + X, ent->position.Y + Y};

if (point.X >= realsize.X)
point.X -= realsize.X;
if (point.Y >= realsize.Y)
point.Y -= realsize.Y;

point.X += realsize.X * j - viewloc.X;
point.Y += realsize.Y * i - viewloc.Y;

if (point.X >= 0 && point.X point.Y >= 0 && point.Y {
tempbuf[point.Y * viewsize.X + point.X].Attributes = (*ent)[Y*ent->Size().X+X].Attributes;
tempbuf[point.Y * viewsize.X + point.X].Char = (*ent)[Y*ent->Size().X+X].Char;
}
} // for each Y-looped point
} // for each X-looped point
} // for each X
} // for each Y
} // for each entity



While I was working on this, I wasn't sure what most of the changes I made actually did! I've tested this a bit (and I've gone through with the debugger) and it looks like it works, so I'm going to start working on an entity-loading system, and then a map system.

Questions about the algorithm? (I know I have plenty!)

Twisol

Twisol

 

Minor changes

I finally got around to fixing the HUD's Add/DelStat functions, since before they were invalidating any iterator (or any index, even) returned from AddStat after DelStat was called. I replaced the internal vector with a list, renamed the functions to HookStat/UnhookStat, and changed it so HookStat takes a statinfo reference... and UnhookStat takes an int pointer. The address of the integer being used as the statistic in the statinfo, actually. It loops through and finds the stat pointing to that, and removes it. Simple enough, I guess.

On the subject of getting entities to draw to the map... This stuff HATES MY GUTS. I'm getting so frustrated trying to figure this out. >_
Meh, g'night.

Twisol

Twisol

 

The 'Entity'

Okay, so after multiple attempts at getting entities to be drawn to the window properly, I've given up for now. Technically, it would "work", but only if the visible location on the window was not a looped-around edge of the map. That means that if the viewloc - that is, the COORD that represents the upper-left corner of the viewing rect - is further to the right or down than the entity's location, the entity isn't drawn, even if technically it should be visible if that location (which is "conceptually" to the left or up from the viewloc) was looped around for the window and is thusly visible.

Actually, writing that gave me some ideas to fix that problem, heh.

Anyways, I decided to beef up my Entity class a bit. Here's the definition:


class entity
{
protected:
CHAR_INFO* sprite;
COORD size;

public:
COORD position;

entity();
entity(COORD theSize);
entity(CHAR_INFO* theSprite, COORD theSize);

virtual ~entity();

int AllocSprite(int sizeX, int sizeY);
COORD Size();

// May throw std::out_of_range.
CHAR_INFO& operator[] (int idx);

};



The end-user - well, technically that's me too - can actually create an extended Entity class that contains additional fields, like Health and Level and Speed for example, that they can use for whatever they want. The GameView only cares that what it has is an Entity. In that respect it's a bit like an interface, except that you can instantiate a bare-bones, base-class Entity.

Sure, I guess you could keep that information (health, level, speed) in a separate structure and not bother with inheritance. It seems like a weak reason to use inheritance, actually. But conceptually it's cleaner to have everything in one spot. Actually, you could take that aforementioned separate structure and just add " : public entity" after the name, and it would work.



It occurs to me that I should explain what some of the member functions of Entity are for. Well, the operator[] allows for easy indexing of the sprite member (and includes bounds checking). AllocSprite() deletes the current sprite if it exists, and re-allocates enough room for a sprite of size (sizeX, sizeY). The position is public because, quite simply, there's no reason for it to be encapsulated. I was going to make it protected, and create get/set functions, but they would have been little more than "position.X = X; position.Y = Y;" and "return position;". Why bother?

Alright, back to mucking with drawing the entity sprites to the buffer. Comment!

Twisol

Twisol

 

Cripes Update

I've made some pretty good progress! I fixed some problems (and overcompensations) in GameView's Hook/UnhookEntity functions, and got rid of the iterator contained in entity. Now you just pass the address of the entity to UnhookEntity. Does the same job, and is a lot cleaner.

Also, up to this point I was assuming that the GameView's map buffer and window were the same sizes. I changed that today, so now it properly shows a window onto the buffer, no matter what size the buffer is. Even if the window is bigger than the map, I think, because I've added in looping maps! If you happen to see, say, further than the right edge of the buffer, the left edge loops over so it's a continuous, infinite map in all directions. Here's how I do it in Draw():


void GameView::Draw(int x, int y)
{
SMALL_RECT writerect = {x, y, x+viewsize.X-1, y+viewsize.Y-1};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

CHAR_INFO* tempbuf = new CHAR_INFO[viewsize.X*viewsize.Y];

for (int i = viewloc.Y; i {
for (int j = viewloc.X; j {
int tempidx = (i-viewloc.Y)*viewsize.X+(j-viewloc.X); // index within the tempbuf
int playidx = i*realsize.X+j; // these two indices refer to the same conceptual location.

// This "sews" the left/right and up/down map edges together, if they're visible.
if (j >= realsize.X)
playidx -= realsize.X;
if (i >= realsize.Y)
playidx -= realsize.X*realsize.Y;

tempbuf[tempidx].Attributes = playbuf[playidx].Attributes;
tempbuf[tempidx].Char = playbuf[playidx].Char;
}
}

COORD topleft = {0, 0};

WriteConsoleOutput(hOut, tempbuf, viewsize, topleft, &writerect);
}



Okay, one thing before I go on. WriteConsoleOutput is wonderfully handy. But I can never, ever remember how to use it properly without looking at the docmentation. >_
The code starts off by creating a few things that WriteConsoleOutput will need, such as the buffer to copy to the console, the console output handle, and the.. um.. Hold on, where's that MSDN link... Okay, that's the rectangle that defines where the buffer will be written to. From there, I iterate through the temporary buffer, and copy each CHAR_INFO from the map to the temporary buffer. The complicated indexing is because the window is offset from the map, so you have to compensate to get the proper indexing. It's ugly.

During the copying, I check to see if a given coordinate value is too far over to the right or down. If it is, I subtract the X or Y value of the size of the map buffer, to achieve a looparound effect. The last two lines of the function create a COORD that defines where the top left location of the rect to copy from is, and then it does the actual writing.

Okay, so. The looparound isn't exactly an obvious effect, but here are two screenies. The blue-background, black-letter A's are just there for testing, to make it look like something's actually there.


This is the window view with no looparound, at least not needed. The edges of the screen are the edges of the map.


This is the window view when you've moved up and to the right a bit. No difference you can see, right? The four specially-coloured spaces were at the top-left of the screen, and now two are on the left and two are on the right.


Next up I'm going to work on adding the entities into the buffer. Right now I'm just using cout (and my color/position manipulators from April, I think) to draw my little green X, when I should really be letting the GameView do that.

Twisol

Twisol

 

Username Change

So, for those of you wondering who in the world Twisol is and why his journal is on your bookmarks - nevermind that linkofazeroth's journal is gone, it was never very interesting - I had a namechange from linkofazeroth to Twisol. Feel free to ask why, you know, anything to get a few comments around here. What are you, comment misers? Sheesh.

There really hasn't been too much of an update since last time. I'm adding support into the GameView for actually using entities though, and changing the HUD like I mentioned last time. I'm afraid to post any screenies too, because the only difference between the last two WAS A GREEN X. Sad...

Twisol

Twisol

 

GameView

I haven't changed anything on the front-end yet, everything has been structural. In the GameView, I'm adding HookEntity and UnhookEntity functions, to pass the GameView an entity pointer. The entity itself is still maintained by the user, just like with the HUD.

There's a couple differences between the HUD's "statinfo" struct and the GameView's "entity" struct right now, although I'm probably going to modify the statinfo struct later anyways. One difference is that the HUD itself holds the statinfo struct, and the user only keeps the int pointer used to modify the value of the stat on-screen. The GameView only keeps a pointer to the entity struct, and the user keeps the entire thing. This lets the user modify more than just one field as well, which is nice.

The other difference is that the entity structure contains an iterator to the entity pointer's location in the GameView's std::list of entity*'s. This seems a bit odd, but it's not actually meant to be used by the user. When you HookEntity() an entity, the GameView stores the entity's list iterator position. You need this iterator to pass to UnhookEntity() so it can find and unhook the right structure. It also points the unhooked entity's iterator to NULL.

A note on HookEntity and UnhookEntity. In the HUD, I use std::vector, so when I DeleteStat, I pretty much break the integer indices I returned from AddStat that are in front of the stat deleted. In the GameView, I use std::list. When HookEntity is called, it first looks for an empty link in the list (where the entity* is NULL). If it can't find one, only then does it push_back on the list. This helps keep down the amount of wasted space in the list, while keeping the iterators in the existing entities valid. Thus, UnhookEntity unhooks an entity and replaces it in the list with a NULL pointer. It also, to keep things clean in the list, checks beforehand if the iterator is at end()-1, or the last item in the list. If it is, it just uses pop_back() to get rid of the link entirely.

I'm probably going to implement those two differences in GameView into the HUD too, because I don't see why not. And because DeleteStat's index-breaking habit is a bug. Comments please? :D

Twisol

Twisol

 

Movement

I've finally figured out movement, heh. Where before I was catching the player input, but not moving the player until the end of the frame, I'm moving the player immediately and waiting a set amount of time until the player can move again. This helps so much, especially as now I can get rid of my previous moveheld boolean, and make my keypress array of integers into a boolean array instead (it had to be integer originally so I knew the key was being held).

With this utterly simplified movement system (whew), adding diagonal movement was a piece of cake. Yay!

Here's a screenshot of the game so far. It's getting there...


Twisol

Twisol

 

Movement

I got the movement thing to work properly, at least in terms of stopping where I want to be stopped. Now I have to get diagonal movement in, and I'll leave it alone unless I really need to do something with it.

In terms of the gameview, I'm not sure how I'm going to have the map loaded in. I tried to hand-copy the map from the original Snipes into a text file, but that didn't work out very well. I could definitely use some feedback on this...

Twisol

Twisol

 

Cripes! update: movement and the gameview

So far so good, I guess. I've got a skeleton GameView class, although at the moment all it does is store a buffer in memory, store the size of the buffer, and store the size of the viewing window (that is, how much of the buffer will be seen on-screen).

On the subject of movement, I've taken the easy route for now and just used cout (and my color/position manipulators from a couple months ago) to draw a player sprite (in fact simply an "X") at the center of the map. Then, during the main loop, where I catch VK_ESCAPE to quit in the last code example I gave, I pass the vkey value to my HandleKeypress function, which changes the values in a "myposition" COORD depending on which arrow key I've hit.

Now, my problem with this was that I would move more than I wanted to allow per frame (that is, one square per frame). I managed to fix that (a boolean "moved", if true then no changing of myposition), but now my problem is a more difficult one: I want to be able to tap an arrow key and have it move once, but also hold it and let it move as long as I want, and let go and stop movement. The letting go is the issue here, because you only let go when you SEE that you're where you want to be, but by then the frame has begun and it's already captured your continually-held movement key. Once you've let go, it doesn't realize that, and so it moves you one past where you wanted, and THEN stops. A real pain, isn't it?

So, currently I'm working through that little hitch, and I'll update again when I've got that working.

Twisol

Twisol

 

About Me

I made a post recently on an announcement topic in the forums called "Hey there! What's your story?", and I realized that the only About Me post I have in this journal was from when I first started it. Things have probably changed a little since a few years ago. :P




^Above taken verbatim from the post I made in the topic

Twisol

Twisol

 

Playing view

Cripes! - The Snipes Clone
So today I really didn't do much with the code itself. I did tweak my HUD implementation though, and I've begun work on keypress handling. Right now I'm just trying to figure out how to get the Cripes! playing view going. I figure I'm going to have a buffer that contains the entire map, and like the original Snipes the map will wraparound so you can step from the left side of the map to the right side. I'm just not sure how I'll implement that at this stage, but I suppose it's minor enough that I can leave it without wrapping for now.

I'm definitely proud of my HUD, it's one of the few parts of, well, anything that I've actually finished and I'm happy with. It could definitely be done better, but I like how easy my system is to use. Someone mentioned that I should modify it so that you can use more than just integers as the stat data, but at the moment I don't need to and I don't want to devote any time to pondering it. Using an analogy I read somewhere around here, I want to build a rope bridge first, and then expand it.


Recent bookreading
I finished my "Breaking Into the Game Industry" book by Ernest Adams, and I loved it. Even though it's a few years old, I think it most definitely still applies, and I highly suggest it to anyone else who is interested in the game industry (career-wise).

"Windows via C/C++", well, it's definitely interesting. I think it's a little too stiff in stylefor my liking, and I have no idea where to start with what I learn from it, but it's definitely an interesting read. It's pretty advanced though... I don't have many of those, heh, so I'm glad I picked it up. But, I've hardly gotten through the first 100 pages, and this is a thick book.

I haven't had a chance to put "World of Warcraft Programming" to use, so I can't say much on it yet. I like what I see though! (Not to mention, characters from the World of Warcraft webcomic "Looking For Group" are on the cover)


...Wow, and I thought this would be a short post. >_

EDIT: I can never get away without an edit, can I? Here's a screenie of Cripes! so far.


Twisol

Twisol

 

Timers

Tonight I worked through my implementation of "timers" a little bit, and fleshed out how I want the game to run a little more. My "delay" techinque, quite simply, was restrictive. Luckily, I found out about the SetTimer function. I had to rework the main loop of my program (as seen in my last journal entry), but I think it was definitely worth it.

My current approach leaves the keypress checking to the main loop, and moves the actual HUD updates to a TimerProc function. I have to create a timer with SetTimer and pass it the address of TimerProc, so during my main loop I also check for messages, and translate/dispatch the WM_TIMER messages. Dispatching the WM_TIMER message, if it was caused by the timer I created, will call TimerProc!

Below is my new and improved main() function, as well as my current TimerProc function.


void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
static bool timestatinc = false;
//Because this function is called every 500ms, I need to keep track
//of whena full second has passed. Only then do I update the time data.

if (timestatinc)
++GameInfo.time;

GameInfo.score += 10;

hud.Draw(0, 0);

timestatinc = !timestatinc;
}

int main()
{
Init();
hud.Draw(0, 0);

if (!SetTimer(NULL, 1, 500, &TimerProc))
return 1;

while (true)
{
int vkey = CheckForKeypress();
if (vkey == VK_ESCAPE)
break;

MSG msg;

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_TIMER)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

KillTimer(NULL, 1);
}





I'm still not sure what the commenters meant in my last post, but I'm pretty sure this approach will be sufficient for Cripes!. Thanks for the input though, always great to have! *hint hint*


EDIT: In other news, my grandmother let me pick out and buy three books, which totalled to $140 total. I know, it's mean for me to do that, but she let me AND she said it would be an early birthday present. "As long as you read them and learn from them, I'm fine!" So, yeah. I'm now the proud-to-semi-proud owner of World of Warcraft Programming (addons and such), Breaking Into the Game Industry (my favorite so far!), and Windows From C/C++ (at $70, I should like this best, but... I don't. It's handy though, and I got the SetTimer idea from it!)

Twisol

Twisol

 

Timed stuffs!

First, a thanks to EasilyConfused for his much appreciated comment. :D

Today I coded in a timed delay thing into the game's main loop. This way things don't go lightning-fast on the player... it's limited to doing stuff once every 500 miliseconds now. I guess you could call each interval the game does stuff in a "frame", yes? I also added a keyboard input function, to check if there was a valid keypress, and return its virtual key identifier (for example, VK_ESCAPE)

Here's my main() function, to show you how the main loop looks so far. I think I just need to work on the actual gameplay now...


int main()
{
Init(); // Sets up the HUD details and console title

bool quit = false;
int timestat = 0; // Because each frame is half a second, I need
// a way to know when to increment the HUD's time
// field - that is, once every two frames.

while (!quit)
{
unsigned long currtime = GetTickCount();
hud.Draw(0, 0); // The arguments specify the x,y coord of the
// top-left corner of the HUD.

GameInfo.score += 10;

if (timestat == 0) timestat = 1;
else if (timestat == 1) { timestat = 0; GameInfo.time += 1; }

// During the delay time, when nothing is being done, I watch for
// keypresses. I used to have it outside the while, but there was
// a visible delay between pressing and exiting when the key was
// pressed after the check and during the delay. Placing it in the
// loop lets me check as many times as the while iterates per frame,
// and because the game doesn't take long to process what I have so
// far, there's no visible delay in quitting.

while (currtime+500 > GetTickCount())
if (CheckForKeypress() == VK_ESCAPE)
{
quit = true;
break;
}
}
}




EDIT: If you're wondering, and I'm sure you are, the game looks no different now than a month ago. The only differences are internal, except that I'm actually displaying the game's data in the HUD, not just the "static" lines. Nothing new though, just zeroes! (Although I use a line of six zeroes as a static to the right of the Score line, so it looks like we've got a sort of zerofilled score going on when the score is drawn on top of it. I likey.)

Twisol

Twisol

 

Update so far

I finished task two of my to-do list today, so now my HUD's data is all stored in files for easy modification. I have the single lines of info (like "Score" and the smiley face characters) in "statics.txt", and the actual data in "layout.txt". The format for the statics is one static per line, in the form "".

For the layout file, things are a little different, because there's a specific number of data items that the game needs to place. There's nine data fields on the HUD, so there has to be a corresponding line for each. The format is just like the statics.txt, but in the form "".

In the end, a chunk of code for laying out the HUD has been taken out. Yay clean code. I think I'm going to work on the timer class next...

(I haven't had comments in ages! A simple "hey, looks good" would be nice XD)

Twisol

Twisol

 

HUDding progress!

Okay, so I have a working HUD implementation up! The code below looks kind of messy, but the thing is, all of it only needs to be run once ever. Except for hud.Draw(), though.. that's obvious, right?

HUD hud(80, 3);
hud.SetBGColor(CC_BLUE);
hud.WriteStatic(string() + char(218) + char(191), 0, 0, CCI_BLACK);
hud.WriteStatic(string() + char(192) + char(217), 0, 1, CCI_BLACK);
hud.WriteStatic(char(179), 6, 0, CCI_BLACK);
hud.WriteStatic(char(179), 6, 1, CCI_BLACK);
hud.WriteStatic(string() + char(1) + char(26), 8, 0, CC_CYAN);
hud.WriteStatic(string() + char(1) + char(26), 8, 1, CCI_BLACK);
hud.WriteStatic(char(179), 16, 0, CCI_BLACK);
hud.WriteStatic(char(179), 16, 1, CCI_BLACK);
hud.WriteStatic(char(2), 18, 0, CC_CYAN);
hud.WriteStatic(char(2), 18, 1, CCI_BLACK);
hud.WriteStatic(char(179), 25, 0, CCI_BLACK);
hud.WriteStatic(char(179), 25, 1, CCI_BLACK);
hud.WriteStatic("Skill", 27, 0, CCI_BLACK);
hud.WriteStatic("Time", 27, 1, CCI_BLACK);
hud.WriteStatic("Score", 27, 2, CCI_BLACK);
hud.WriteStatic("Men Left", 2, 2, CCI_BLACK);

statinfo si; // One statinfo to be copied for them all
si.alignright = true;
si.color = CC_CYAN;
si.pos.Y = 0;

si.theStat = &GameInfo.doorsshot;
si.pos.X = 4;
hud.AddStat(si);

si.theStat = &GameInfo.snipesshot;
si.pos.X = 14;
hud.AddStat(si);

si.theStat = &GameInfo.ghostsshot;
si.pos.X = 23;
hud.AddStat(si);


si.color = CCI_BLACK;
si.pos.Y = 1;

si.theStat = &GameInfo.doorsleft;
si.pos.X = 4;
hud.AddStat(si);

si.theStat = &GameInfo.snipesleft;
si.pos.X = 14;
hud.AddStat(si);

si.theStat = &GameInfo.ghostsshot;
si.pos.X = 23;
hud.AddStat(si);

si.theStat = &GameInfo.lives;
si.pos.X = 0;
si.pos.Y = 2;
si.alignright = false;
hud.AddStat(si);

hud.Draw(0, 0);


Internally, the HUD class contains a "static information buffer", where information that shouldn't be altered often if ever is held. This is where the bits like "Men Left" and the symbols and stuff are held, as well as the HUD background color for each cell. WriteStatic writes a character string (or single character) to that buffer, with the specified forecolor.

Next, I create a statinfo object. AddStat() copies, so we don't have to worry about creating a statinfo for each stat. The statinfo struct contains four members: an int* pointer to the data for the HUD, a positioning COORD, a forecolor WORD, and a boolean that sets whether it should be aligned to the right or not (if true, the position is treated as the location of the last character in the data, instead of the first).

Then, I Draw() the HUD to the screen. The arguments specify where the upper-left corner of the HUD will be put. After all this, all you need to do to change the values on the HUD is change the values that you gave to the statinfo objects! The only thing you need to do is Draw() the HUD again.

The thing I like most about this, though, is that the HUD has its own buffer. All it does to interact with the actual console is print its buffer to the area it wants to. So its internal buffer is only as large as the size parameters passed to it at the start, and I have no worries about ruining data held by the gameview area.

Pic!

Twisol

Twisol

 

HUDding

I talked to my VB .NET teacher at college on Tuesday, and he gave me some ideas on how to tackle this project. I suppose this one should have been obvious, but the one I've taken to heart at the moment is modularizing things... or at least, building each component separately and getting it to work. So, I had to scrap what I had so far of the HUD (although, to be honest, it was ugly anyways).

Right now I have a pretty bare-bones HUD class that can be created with any size, a background color set, and drawn to the window at any location. It looks good, and a whole lot cleaner than what I had before. I'm planning on keeping the HUD buffer separate from the gameview buffer, too, by having a single buffer internally in the HUD that is only the size of the HUD itself, and drawing that buffer to the location on the console. Same goes for the gameview section.

Next up: adding a list of "stats" for the HUD to show. I'm just going to create a structure to contain the information for each stat, and have the HUD hold a vector of them. That's for tomorrow, though!

Twisol

Twisol

 

Cripes! To-do list

Cripes!
I didn't do much on Cripes! today, except work a little on the HUD. So far all of the values are hard-coded, although I'm going to try storing those values in a file eventually.


Short-term goals:

Finish the basic look of the HUD.
Store character and color values in files
Create some walls and the player sprite
Add a timer class!


EDIT: Forgot to add one!

Miscellaneous
A friend of mine asked me to convert some Java functions into Perl scripts for him, which encode and decode stuff with BASE64. It was.. definitely interesting getting the code to fit. For one, in Perl there's no explicit "char" datatype, so the range of values far exceeds the typical char. This becomes a problem when the algorithms used to encode/decode use bitshifts, apparently... I managed to create a Perl subroutine that checked a given character (assumed to be in the range [0, 255]) against the typical signed char range, [-128, 127]. That is, if the value is 128 or over, it subtracts the value from 256 and negates it. To my amazement, heh, it worked.

Then came a problem with the encoder where it wasn't pulling in all of the characters. Apparently, because I was getting one character at a time and checking if that was a '\0' for the EOF, it ceased to parse the file if it encountered the -127 character value. I eventually just pulled the file in line by line (the EOF is handled for me), join()ed the resultant list, looped through it again pack('c', $myChar)ing each, and converted the list into a string. Seems klutzy, but it worked!

The end result: two perl scripts that take an input filename and an output filename via the command line, reads in the input, and writes the encoded/decoded data to the file. Woo.

Twisol

Twisol

 

Snipes clone: "Cripes!"

Well, I've decided to try my hand at a Snipes clone. I've worked a little and decided that my console manipulators wouldn't be much help, although they were just a little side project anyways. I haven't found a clean way to do what I want yet, for a few reasons, but here's a picture of what I have so far:



Yeah, it's hardly anything but an almost empty status bar and a completely empty gameplay box, but it's getting there. I hope.

Twisol

Twisol

Sign in to follow this  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!