|
In order of no progress to done:
Red,
Orange,
Yellow,
Blue,
Light blue,
Green,
Light green.
Last updated 2/12/09 at 12:01 am PST
Cripes! 2.0 -- See the Class Layout
Arenamatic Code w/ cConsole
 Entity drawing! |
Posted - 6/29/2008 5:48:26 PM | 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<entity*>::iterator itr = entities.begin(); itr != entities.end(); ++itr)
{
entity* ent = *itr;
for (int Y = 0; Y < ent->Size().Y; ++Y)
{
for (int X = 0; X < ent->Size().X; ++X)
{
for (int j = 0; j <= loopedtimes.X; ++j)
{
for (int i = 0; i <= loopedtimes.Y; ++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 < viewsize.X &&
point.Y >= 0 && point.Y < viewsize.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;
}
}
}
}
}
}
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!)
| |
 Minor changes |
Posted - 6/27/2008 4:20:24 AM | 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.
| |
 The 'Entity' |
Posted - 6/26/2008 2:10:47 AM | 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();
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!
| |
 Cripes Update |
Posted - 6/22/2008 4:18:23 AM | 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 < viewloc.Y+viewsize.Y; ++i)
{
for (int j = viewloc.X; j < viewloc.X+viewsize.X; ++j)
{
int tempidx = (i-viewloc.Y)*viewsize.X+(j-viewloc.X);
int playidx = i*realsize.X+j;
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.
| |
 Username Change |
Posted - 6/19/2008 1:26:32 PM | 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...
| |
 GameView |
Posted - 6/16/2008 9:44:29 PM | 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
| |
 Movement |
Posted - 6/13/2008 2:21:39 AM | 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...

| |
 Movement |
Posted - 6/6/2008 5:16:36 PM | 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...
| |
 Cripes! update: movement and the gameview |
Posted - 6/5/2008 8:23:58 PM | 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.
| |
 About Me |
Posted - 6/1/2008 3:03:49 PM | 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
Quote:
Jonathan, age 15, codes in his spare time in his bedroom. He has quite a lot of spare time, actually, being homeschooled, but he procrastinates so much he only has a fraction of that mound of time left for coding. He wants to eventually go to Digipen for game programming studies, but at the moment is trying (and somewhat failing) to make a finished text-mode game clone, specifically Snipes.
Also starting to feel slower than most even though he had an IQ test when he was younger with quite good results, due to the fact that most people he sees here began coding at 9 and making good progress. Jonathan himself started at 9 years of age with basic HTML, which he liked, moved on to Java, which he didn't (ew, "private static void main", wtf?), and finally got into C/C++, which he really likes. He's also taking math courses at the local community college, and next semester he plans on taking a Java course. (Up till now, he's been taking Visual Basic .NET classes. He wishes he hadn't.)
</end third person>
((And yes, I do understand what "private static void main" means now!))
|
^Above taken verbatim from the post I made in the topic
| |
|
| S | M | T | W | T | F | S | | 2 | 3 | 4 | | | 7 | 8 | 9 | 10 | 11 | 12 | | 14 | 15 | | 17 | 18 | | 20 | 21 | | 23 | 24 | 25 | | | 28 | | | | | | | |
OPTIONS
Track this Journal
ARCHIVES
August, 2009
July, 2009
March, 2009
February, 2009
December, 2008
November, 2008
October, 2008
August, 2008
July, 2008
June, 2008
May, 2008
April, 2008
November, 2007
July, 2007
June, 2007
May, 2007
April, 2007
March, 2007
February, 2007
December, 2006
October, 2006
September, 2006
July, 2006
May, 2006
April, 2006
|