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

About this blog

My not-so daily posts on my current console project

Entries in this blog

 

Cripes 2.0: EntityLoader

Progress! I've created an EntityLoader class which can load entity definitions from a file with LoadFile(), and return a ready-made Entity to calling code with ConstructEntity(). To try it out, I hand-wrote a Player entity definition into a file and had EntityLoader load it, then I passed the result of loader.ConstructEntity("Player") to the entity map's AddEntity method. Works great! ^_^

EDIT: Class layout updated. Also, I added a link to it at the top of the journal, by the color-coded project name.

Twisol

Twisol

 

Cripes 2.0: EntityMap

Just a little update on the Cripes 2.0 design. I changed the EntityManager class into an EntityMap class - a cosmetic change - so I could rationalize giving it a width and height, for the reasons I mentioned before. With that done, I created a Clip() function like the Map class's, and moved the code I previously had in the World for mapping adding the entities to the EntityMap. Much better! Just get the clips, copy the entity clip onto the map clip, and voila.

Slight problem (but very easily fixed): Copying the entity map directly onto the map clip overwrites the map clip entirely. This is bad. Luckily, I thought ahead and decided that '\0' signified "air", as opposed to ' ', which looks the same but is still physically "there". Perfect solution: only copy an entity map block if the character isn't '\0'. Of course, now I'm wanting for a way to designate a clear foreground/background color, but I really don't need it. It would be cool... but I just don't need it, and it's less trivial than this. Oh well! ^_^

EDIT: Yes, this means I can have sprites with holes in them through which you can see the map. Whole lot of good it does me when the Snipes world is just black with blue walls, eh?

EDIT 2: Class layout updated!

Twisol

Twisol

 

Cripes 2.0: Entities are working!

At least, they're drawing properly. I got fed up with my code chopping off bits of our poor Sniper, so I went back into the code for Cripes 1.0 - which I dumped in favour of taking a different approach on the code - and got the entity drawing algorithm I had there. I am very, very glad my younger self solved this problem for me already! What my younger self didn't solve is collision detection, which may prove difficult in Cripes 2.0, as well, since the map and the entities are logically separated.

Oh, but then an idea strikes me! (Or was it just a ">boot to the head?) Maybe I can implement the walls themselves as entities. Hmm! That idea needs to be slept on, but I like how it sounds.

EDIT: Oh, -AND- my primitive multiple-frames-per-Entity animation setup works. It's incredibly primitive - just multiple frames and a current_frame indicator - but it does work. It needs some fixing to make it work the way I want it to, though. But it works! ^_^

Twisol

Twisol

 

Cripes 2.0: Entity visuals

I scrapped the EntityManager and merged it into World. I want to change that at some point, but it works right now and I'm determined to make some kind of progress here.

I know how everyone loves screenshots, so here's one with the Snipes hunter guy (Sniper).

Hello, Sniper!


Uh oh, a bug sliced him in half...


EDIT: I know, the colors are death to the eyes. I needed something to fill the map though! When the map is created it cycles through each of the 16 console colors and sets it as the background color in each cell.

Twisol

Twisol

 

Cripes 2.0: Entity progress

Alright, so I have a barebones EntityManager class up, which maintains a std::list of Entity instances. Each Entity has a std::vector of sprites, intended to be used as frames in Entity animation. I guess it's mostly just there to look good right now, since I'm not really too sure how I'm going to implement the sprite animations. Anyways, the entities are owned by the EntityManager, and Add() returns a pointer to the Entity in its list. I don't think std::list moves its elements around in memory like std::vector does, which is why I think it'll work fine.

This is all a learning process for me, obviously: this is my first real game project. So I guess I shouldn't be too surprised when things go wrong.

EDIT: Something went wrong! If I want the EntityManager to construct a CHAR_INFO clip with the entities - an entity map, basically - then it needs to know how big the world is for wrapping to work properly. Building this entity map in World leaves a bad taste in my mouth, because after all it's getting a ready-made clip from Map. I can't pass the world dimensions to the EntityManager because I don't think it should have that information, either. There has to be a better way :/

Twisol

Twisol

 

Cripes 2.0: World changes

(Three posts in a day! Yaay...)

After mulling my previous idea over (this one) and bringing it up on IRC (general approval), I put it into action. It was more or less pretty seamless, except when it came to Draw(). I wasn't altogether sure whether World should clip the Map down itself, or somehow cut out that code and have the Map return the clipped area to the World itself. I opted for the latter, because it made more sense than the former, even if it was a bit harder.

So now, the Map has a Clip() function that does exactly what it sounds like, and cuts out a section of the map, puts it in an appropriately-sized buffer, and returns it. It does something I'm not altogether happy with, which is new[]'ing memory inside Map that it expects the calling code (World) to delete[], but I can't reasonably pass a buffer to it because once it figured out the proper clip sizes it would have to allocate it itself anyways. It makes sense this way, at least, even if the ownership isn't what I'd like.

Class layout updated accordingly. Next up, the entity manager!

Twisol

Twisol

 

Cripes 2.0 Class Layout

Last updated: 4:49pm on February 17th, 2009

It occured to me while I was writing my last post that even though I might know what these classes do, if I just toss the names out there carelessly the post might take a little work to decipher. So, for my reference and others', here's a class layout for Cripes 2.0 as of now. I'm going to update this post when I add new classes, so don't count on this post staying the same.

Heirarchy:
Game
-Keyboard
-World
--Map
--EntityMap
-EntityFactory

"Independent" classes (granular classes possibly used in multiple places)
Entity
MazeGen


Class: Game
Purpose: This is where my game loop is. I'm not actually sure what Game's exact purpose is. I just think of it as a pseudo-main()-plus-globals thing. This is because my main.cpp is just a main() with a constructed Game and a call to Game::Run(). It remains to be seen whether that's a good idea. (I like to think it is)

Class: World
Purpose: Patches together the components of the visual world, including the world map and its entities. Can be Draw()n, which gathers the clips of the components and copies them together, drawing to a given console buffer (or STD_OUTPUT_HANDLE if none is supplied).

Class: Keyboard
Purpose: Maintains an internal state map of the keys on a keyboard. Its Update() function should be called once per frame. Every key has four possible states, numbered 0 to 3: inactive, down, held, and releasing. When a key is hit, it enters the down state on the next Update(). If it's still down during the next Update(), it's promoted to held. If a key is down when it's released, it's moved to releasing, then inactive. This is to give the program a chance to handle the key before it's released, as it only goes into releasing if it was tapped and released within the same frame/update. If a key is held when it's released, it's moved directly to inactive.

Class: Map
Purpose: Constructs and maintains a CHAR_INFO buffer representing the game map. It can be Clip()ped, trimming the viewing clip given a viewport width and height and returning the result. Some fun cartesian/geometric math here which 'sews' the opposite edges of the map together.

Class: EntityMap
Purpose: Keeps track of an Entity list, and can create a Clip() just like the Map can. There's some -really- fun code involved in the clipping. Yes, maybe even more fun than the Map code! *shudder*

Class: Entity
Purpose: Contains a vector of CHAR_INFO sprites (all of the same dimensions) that can be used as frames for animated sprites. Also has coordinate variables which the EntityMap uses to determine where the entity is on the map.

Class: EntityFactory
Purpose: Factory class that can load Entity definitions from a file and store them in a std::map with string identifier keys. If there's a Player defined in the file, calling ConstructEntity("Player") returns an instance of an Entity with the defined Player frames and size.

Class: MazeGen
Purpose: Constructed with an EntityFactory pointer, it Generate()s a vector of wall Entities given a maze width/height (in cells, not pixels). See this page for the algorithm I use to generate a maze.

Twisol

Twisol

 

Cripes 2.0: EntityManager

Moving on from the Keyboard at last, I'm next going to work on the entity system, including the moving enemy sprites and bullets. I'm hitting a few design walls right now, though. I don't want my Game class to have to handle the drawing of the entities when most of my drawing code is already in the World class, but I don't want World to own the EntityManager because I want the World to just manage one thing: the world map drawing. I guess I could move the map drawing/managing to a Map class, and give the World class a Map and an EntityManager. That sounds a bit better (yes, I'm thinking as I write, it's quite productive, give it a try sometime). That way, the Game code doesn't have to change at all - it would still just world.Draw(). Yeah...

How's that sound? :/

Twisol

Twisol

 

Cripes 2.0: Keyboard Input

After a month or so of mucking around without any work on Cripes, I sat down today and reacquainted myself with the code. I looked over the Keyboard class, thought about it, and came up with something I thought might work if I went with it.

I don't remember if I had written about this before - I must have, (you did -Gaiiden) it was such a major thorn in my side - but since handling keypress input with the console isn't very easy, I was having a tough time coming up with a reliable way to get user movement input. I'm sure I wrote about this, so I won't go into a lot of depth there. But today, I decided to just lay out the behavior I expected from a keypress, and figure out how the Keyboard class should respond with each possibility. In the end, I gave each key in the Keyboard four possible values, from 0 to 3. 0 is inactive, 1 is pressed, 2 is held, and 3 is releasing. I didn't think I'd need a 3 at first, but it fit like a charm when I realized I needed it.

Cripes has the Keyboard Update() itself once per "frame". Before, when a key was both pressed and released before Update() was called, it was like the key was never even hit. Obviously, though, it -was-, and I wanted Cripes to register that. So, when Update() is called, every keydown on a button in the 0 state gets incremented to 1. If a key was in 1 already, it gets incremented to 2, but 2 is as far as it goes. If a key is -released- and it was in 1, it gets moved to 3 first, then next Update() it automatically gets moved to 1. That way it has a chance to be acted on. 2 gets no such special treatment: you're already holding it, if you release it you want to stop -there-!

Here's the code for Keyboard::Update() now. It's not the best, but considering what I have to work with, it's good enough.


void Keyboard::Update()
{
// pre-update key status from last round
for (int i = 0; i 256; ++i)
{
if (keypress == 1) keypress = 2;
else if (keypress == 3) keypress = 0;
}

// variable setup
INPUT_RECORD* records = NULL;
DWORD numEvents;

// stop if there's nothing to update
GetNumberOfConsoleInputEvents(hIn, &numEvents);
if (numEvents 0)
return;
records = new INPUT_RECORD[numEvents];

ReadConsoleInput(hIn, records, numEvents, &numEvents);
for (DWORD i = 0; i {
if (records.EventType == KEY_EVENT)
{
if (!records.Event.KeyEvent.bKeyDown)
{
if (keypress[records.Event.KeyEvent.wVirtualKeyCode] == 2)
keypress[records.Event.KeyEvent.wVirtualKeyCode] = 0;
else
keypress[records.Event.KeyEvent.wVirtualKeyCode] = 3;
}
else if (keypress[records.Event.KeyEvent.wVirtualKeyCode] == 0)
++keypress[records.Event.KeyEvent.wVirtualKeyCode];
}
}
delete[] records;
}





Twisol

Twisol

 

Hi-bye

Just popping in. No progress on Cripes since yesterday, I've been too busy finishing my C++ class lab project (due today, of course) and homework (also due today). Hmm, sounds familiar? I waited until the last day to apply to USC, too. How.. disturbing.

Both homeworks are finished now, at least, and I feel good about them.

~Jonathan

EDIT: I may be saving up for an Xbox 360. Everyone I know seems to have one, and they all like it. I think Mirror's Edge was the final straw.

EDIT (time: 10:19pm PST): Just got back from class. I think I'm going to take the night off and play some Wii, I've been a bit stressed lately.

Twisol

Twisol

 

Keyboard and USC

Cripes!, the Snipes clone
I've been hard at work on the Keyboard class for the past few days. It's taken me longer than I thought to wrap my head around how to approach interactive keyboard input, but I'm getting there. The Keyboard class now has an Update() method to scan for keyboard events and toggle its internal boolean array accordingly; a WaitForKeypress() method that blocks while waiting for a keydown event; and a Pressed() method that returns the number of keys currently down. The Pressed() method is mainly to help work around the fact that if one key is held down, then another key is pressed and released, the initial key stops sending repeating keydown messages. It does, however, send a message when it is released.

So far it works pretty well, the only problem being that holding the arrow key down causes the world to scroll blazingly fast. I'm pretty sure that's just a problem with how I'm responding to input, not with the Keyboard class itself. Browsing through MSDN while I type this reveals that a waitable timer combined with WaitForMultipleObjects() may solve that, though it's just an idea for now.


College Application - USC
About four hours ago, I finally finished my application to the University of Southern California. The deadline is December 1st.. that'd be today. Cutting it a bit close, eh? Here's hoping I get in! :)

~Jonathan

Twisol

Twisol

 

Keyboard input

With the help of some of the folks on IRC, I finally got some basic user input working. And it doesn't hog the CPU, either! I think the code speaks better than I can this time.


bool Game::Update(INPUT_RECORD* records, DWORD numEvents)
{
bool retval = false;
for (DWORD i = 0; i {
if (records.EventType == KEY_EVENT)
{
if (records.Event.KeyEvent.bKeyDown)
{
switch (records.Event.KeyEvent.wVirtualKeyCode)
{
case VK_UP:
retval = true; y -= 1; break;
case VK_DOWN:
retval = true; y += 1; break;
case VK_LEFT:
retval = true; x -= 1; break;
case VK_RIGHT:
retval = true; x += 1; break;
}
}

keypress[records.Event.KeyEvent.wVirtualKeyCode] = (records.Event.KeyEvent.bKeyDown != 0);
}
}
return retval;
}

int Game::Run()
{
Draw();

INPUT_RECORD* records = new INPUT_RECORD[1];
DWORD numEvents = 1;
bool redraw = false;

while (ReadConsoleInput(hIn, records, numEvents, &numEvents))
{
redraw = Update(records, numEvents);

if (keypress[VK_ESCAPE])
break;

if (redraw)
{
Draw();
redraw = false;
}

GetNumberOfConsoleInputEvents(hIn, &numEvents);
if (numEvents)
{
delete[] records;
records = new INPUT_RECORD[numEvents];
}
}
delete[] records;

return 0;
}



It's very basic right now, but most of that is going to go into that Keyboard class I mentioned (currently not being used). While I was working this out, I was using a while (true) loop. That turned out to be a very bad idea, because when I opened up the Task Manager, Cripes was sucking up almost 20% of my CPU time. I figured this version out, luckily, which uses far less CPU time because ReadConsoleInput() blocks when there's no input in the buffer.

This code will definitely be changing, mostly as I move code into the Keyboard class and start utilizing it in Run(). For now I'm just glad I can kinda-sorta move the map around. :P

~Jonathan

Twisol

Twisol

 

User Input Hassles

I'm not actually sure how to proceed here. User input is easy enough on its own, but I need to continually Draw() at a certain framerate as well as watch for user input (and act on it wen it comes in). I created a Keyboard class, but I'm really not sure how to do this.

I want to draw, at the moment, once every 0.25 seconds. I also want to watch for user input constantly, and move the "camera" every time a key is pressed (but only allow them to move once every so often). And I don't want to continually loop, because I think that hogs CPU; I just want to do something if there's something to do, or it's time to draw.

The only thing I've managed to do, that works in some respect, checks the console input buffer every time through the loop and sets the appropriate element in an array of bools depending on what key event comes through. Then it draws, and Draw() checks the time elapsed between the last time we drew and now, and if we're good to go, it checks the arrow key booleans and moves accordingly. The problem here is that it only works if we held the key down when Draw() actually draws. If we hit an arrow key after 50ms since the last Draw(), and let go at 100ms since the last draw, it's like we never hit the key at all - Draw() doesn't recognize that we tried to move. And it keeps looping whether we have anything to do or not.

Obviously I'm new to handling keyboard input like this. I think WaitForMultipleObjects() could help (because it can wait on an input buffer handle), but I still have no idea how to proceed. A poke in the right direction would be hugely appreciated! =\
~Jonathan

Twisol

Twisol

 

Wrapping world display

I just finished adding a wrap-around functionality to World::Draw(), with a boolean parameter to enable it. It was actually a lot simpler than I thought it would be. In the previous version, without wrapping support, I had to clip the SMALL_RECT parameter entirely down to [0, width) and [0, height). In this version, I put the clipping code in an if-statement, only to be run if the wrap flag is false. Within the loops that map each World buffer index to a temporary buffer, I calculate the indexes with modulo, and if it's a negative result, I subtract it from width/height (because it's already floored down to that range). Here's the final code:


BOOL World::Draw(SMALL_RECT& clip, COORD drawloc, bool wrap) const
{
if (clip.Left > clip.Right || clip.Top > clip.Bottom)
throw std::exception("Bottom/Right cannot be greater than Top/Left!");

if (!wrap)
{
if (clip.Left 0) clip.Left = 0;
if (clip.Top 0) clip.Top = 0;
if (clip.Right >= width) clip.Right = width - 1;
if (clip.Bottom >= height) clip.Bottom = height - 1;
}

int view_width = (clip.Right - clip.Left + 1), view_height = (clip.Bottom - clip.Top + 1);

if (view_width == 0 || view_height == 0)
throw std::exception("Viewing dimensions too small.");

CHAR_INFO* buf = new CHAR_INFO[view_width*view_height];

for (int y = 0; y {
for (int x = 0; x {
int world_x = (x + clip.Left) % width,
world_y = (y + clip.Top) % height;

if (world_x 0) world_x += width;
if (world_y 0) world_y += height;

buf[x+(y*view_width)].Attributes = buffer[world_x+(world_y*width)].Attributes;
buf[x+(y*view_width)].Char = buffer[world_x+(world_y*width)].Char;
}
}

SMALL_RECT writeloc = {drawloc.X, drawloc.Y, view_width+drawloc.X-1, view_height+drawloc.Y-1};
COORD bufsize = {view_width, view_height};
COORD origin = {0, 0};

BOOL retval = WriteConsoleOutput(screen, buf, bufsize, origin, &writeloc);
delete buf;
return retval;
}






I also noticed this time around that I had a memory leak on the last line. Originally I was just returning the return value of WriteConsoleOutput(), but I had completely forgotten to delete[] the temporary buffer I passed to it. The last three lines here solved that.

So it wasn't nearly as hard as I thought it would be. Awesome!

~Jonathan

Twisol

Twisol

 

Entry in Progress

I'm writing an entry here right now, so stay tuned for edits!

(Though currently I'm also late for a programming class. I'll be able to write from there, though)

~Jonathan

Twisol

Twisol

 

More World drawing

First things first: [insert paragraph of rage]. I just lost everything I typed out for this post because I lost my internet connection right when I hit Reply. ARGH.

*sigh* Okay... After some comments and discussion on #gamedev, I decided to get rid of World::View and the DrawView functions. I replaced them with two functions, SetScreenBuffer() and Draw(). The first sets the console screen buffer to draw to (via a HANDLE), and the second draws the World to the screen. Draw() is important here; I'm sure you can figure out in about five seconds how SetScreenBuffer works.

World::Draw() takes two parameters: a SMALL_RECT& defining the viewing rectangle, and a COORD specifying the upper-left coordinate of the view, relative to the screen buffer being drawn to. Being able to specify the screen buffer via SetScreenBuffer() can be useful in case you want to do double-buffering or something, but in this case it's useful because I created a new buffer for the console, and I want World to draw there instead of the original buffer. (Hey, look at that, the last few lines in the editor all begin with "buffer" at the beginning. Including this one! ^_^)

EDIT: I was going to add something into this past paragraph, but I didn't want to break the line of 'buffer' >_>. You can use an offscreen buffer to edit what the View gives you, too. For example, changing the background color or odd things like that. You could draw entities in at this stage too, sprites and whatnot, but in this case, I'm going to let the World handle that.
--END EDIT

Here's the code for Game::Draw(), which calls World::Draw(). It includes the older version of the code too, for comparison.

void Game::Draw()
{
/*/
/// Old version
World::View worldview = world.CropView();
SMALL_RECT drawRect = {0, 3, worldview.Width()-1, worldview.Height()+2};
COORD origin = {0, 0};
COORD worldsize = {worldview.Width(), worldview.Height()};

WriteConsoleOutput(hOut, worldview.CharInfo(), worldsize, origin, &drawRect);
/*/
/// New version
SMALL_RECT cliprect = {0, 0, world.Width(), world.Height()};
COORD drawloc = {0, 3};
world.Draw(cliprect, drawloc);
//*/
}

The first thing I noticed was that it's much easier to specify where to draw, not to mention to see where the drawing coordinate are in the first place. The old version had them integrated into the drawRect. In the new version, everything looks much clearer, and concise too.

Incidentally, this approach makes it a bit easier to add a flag to World::Draw for wraparound views. That is, if the right edge of the map is visible near the middle of the viewing rect, the left edge adjoins to it and continues to the right, wrapping around like a cylinder or sphere. (You don't sail off the edge of a cartographical map, you return to the opposite edge)

Also note the interesting assortment of comment blocks here. Each of the comments with a * in it acts as part of a toggling structure, with the first /*/ acting as the switch. If the switch has two stars (or zero), the old version code is active. If it has only one, the new version code activates. I thought it was nifty.


~Jonathan

P.S. This post is waiting for me to send it right now, because the internet is still down. Thankfully, I saved it to a text file this time, just in case.

Twisol

Twisol

 

World::View

Today (and partially last night) I wrote up a View class to wrap the clipped view of the World returned by World::DrawView(). It's constructible only by World (excepting the copy-ctor, which is public), taking width and height parameters to create a dynamically-allocated CHAR_INFO buffer. It overloads the [] operator and a conversion operator (because it was easy and it makes sense), and handles the buffer's memory itself.


class View
{
private:
CHAR_INFO* view;
int width, height;

View(int width, int height);
friend const View World::DrawView(int, int, int, int) const;
public:
View(const View& v);
~View();

View& operator=(const View& v);
CHAR_INFO* const operator[] (int idx);
operator const CHAR_INFO* const() const;

int Width() const;
int Height() const;
};




This is all I need to do to draw my world view to the screen:

void Game::Draw()
{
World::View worldview = world.DrawView(0, 0, world.Width(), world.Height());
SMALL_RECT drawRect = {0, 3, worldview.Width()-1, worldview.Height()+2};
COORD origin = {0, 0};
COORD worldsize = {worldview.Width(), worldview.Height()};

WriteConsoleOutput(hOut, worldview, worldsize, origin, &drawRect);
}

Notice that I can pass worldview to WriteConsoleOutput? That's the conversion operator (converts to const CHAR_INFO* const). I think it looks really clean. DrawView() takes the xy coordinates of the upper-left and lower-right rectangle to view. Technically, passing the world's Width and Height puts the rect one over the edge on the right and bottom sides, but DrawView clips it down, so it's a small shortcut rather than subtracting one from each. Then again, I have to do it in the drawRect anyways...

Twisol

Twisol

 

Console buffers and learner's permits

Cripes! - The Snipes clone
After doing a little more reasearch, I tried using CreateConsoleScreenBuffer() to create a separate buffer for Cripes to draw to. It turns out that separate screen buffers keep separate state, so I don't really need to worry about saving the old state. My Game class constructor handles the set-up of the console window, and here's the source code:


Game::Game()
: hOut(CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL)),
hIn(GetStdHandle(STD_INPUT_HANDLE)),
hPrev(GetStdHandle(STD_OUTPUT_HANDLE)),
world(40, 25)
{
if (hOut == INVALID_HANDLE_VALUE)
throw std::exception("Unable to create new console buffer.");
else if (hIn == INVALID_HANDLE_VALUE)
throw std::exception("Unable to access console input buffer.");

if (!SetConsoleActiveScreenBuffer(hOut))
throw std::exception("Unable to set the active console buffer.");

SMALL_RECT win_size = {0, 0, 39, 24};
SetConsoleWindowInfo(hOut, true, &win_size);
COORD buff_size = {40, 25};
SetConsoleScreenBufferSize(hOut, buff_size);

SetConsoleTitle("Cripes 2.0 - A Snipes Clone");

CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = false;
SetConsoleCursorInfo(hOut, &cci);
}








It's actually more simple than I expected. The initializer list sets up the handles and gives our World its dimensions, and the block of if-statements makes sure they're all valid. The next block of code sets the window size, then the buffer size. You actually have to do it in that order here, otherwise we'd set a buffer smaller than the window, which Win32 doesn't like. Then we set the title, and I make the cursor invisible. Take a look:



It actually looks like a normal window filled with a solid blue color. Or it would if the icon didn't scream "CONSOLE!!" I made it that color via a world.FillColor() function I'm using for testing purposes only, so I can see if this stuff is working properly. It is.


Day-to-day Life
I just got my driver's permit. The written test I took allowed a maximum of eight mistakes. I made seven. At least I passed. I'm just a little nervous about driving for my first time... make that really nervous. :|

~Jonathan


EDIT: I don't know what happened here, but it sure looks interesting!

EDIT 2: Ah, I botched my conversion from 2D coordinates to 1D indices.

Twisol

Twisol

 

World view and map generation

Don't get all excited, I haven't gotten all that far from where I was last night. I've been working on the world view (typename changed from WorldView to World) and I think I have a far better design for it than last time. The World is constructed with a world width and height, and it doesn't care in the least what part is viewable. I think that makes more sense anyways.

World also has a DrawView method that takes the width and height of a viewing window, and the upper-left coordinate of the area to be displayed. It currently returns a CHAR_INFO pointer to a dynamically-allocated buffer, but I don't like having 'new' in one class and 'delete' in a whole different one, so I might be wrapping it into a new WorldView class representing the viewing area, with the new and delete calls both in the same logical area. Comments on that idea would be welcome.

Now, about the map generation bit. I replayed the Snipes game, downloaded from here if I didn't post that already, and I've come to the conclusion that the maze is randomly generated each run. I think I'm actually excited about that... but I really, really want to get the core elements in first.

One thing I'm not quite so keen on is the collision detection, although I think it was so horrendous before because of bad design. But yeah... back to World coding.

~Jonathan


EDIT: I can't speak for the rest of Win32 - I've never used it in depth - but Microsoft did a great job on the console functions. I just found [Get|Set]ConsoleCursorInfo functions, easily removing the annoying blinking cursor from the screen. I'm being careful to save the original values of things like the title and the cursor settings, so I can return them to normal when the program is finished. I'm not honestly sure what would happen if I left them like that when the program finished, and I had run it from cmd.exe myself.

Twisol

Twisol

 

Commitment issues (no duh)

If you haven't noticed, I seem to have some issues committing myself to any particular goal. I know plenty of you have had the same problem with projects, past or present, but it seems to be really ingrained with me. And unfortunately I'm not sure what to do about it, because it's heavily tied into my over-achieving nature. And I -like- everything I do, the problem is the jack-of-all-trades-master-of-none thing. Bleh.

Well, I've finally gotten back to Cripes, starting from scratch. Yes, I'm icing the MUD. It was more than I expected... plus VMware with Ubuntu wrecked havoc on my internet connection. Anyways, I'm putting effort into the game view first, because I know I can do the HUD just fine. That was about the only part I actually finished the first time around, although I want to run over it again later on. We'll see how it goes. Here's a list of my previously finished projects though, just because.

Finished projects:
-Console color/position manipulators
-cConsole (it's a beast, but it's reasonably done)

Unfinished projects:
-"Link's Grand Quest" - my first program ever, and according to my critics, my best work. *groan*
-Arenamatic
-eMUD
-Cripes (in progress)


~Jonathan

Twisol

Twisol

 

Short update

I haven't really done anything with ExplorerMUD lately, mostly because I want to try to understand boost::asio first. So it may be at least a week before I actually get something working. I'm sure it'll be worth it though.

In other news, I came up with a brilliant - at least, I think it is - storyline for a book, so I've been spending some of my time writing that out. My lips are sealed, though I may say occasionally if I've finished a chapter or something. :)

Lastly, while using the wonderful Pandora.com, I discovered a relatively new artist, Owl City. I'm listening to both albums pretty much non-stop right now... I'm sure I'll get sick of them eventually, but for now they sure keep my spirits up. I highly recommend "Designer Skyline" and "The Saltwater Room".

~Jonathan

Twisol

Twisol

 

Brief Interlude

I'm taking a Beginning C++ class at my community college right now. It's very basic, no classes or objects yet, even - that's for the next class - but it sort of helps when you have to do certain things. I'm definitely learning some minute details.

With my experience beforehand, though, I'm acing this class handily. Woohoo!

No further progress with eMUD yet, I'm giving it a day to rest. Though here's a free plug to Achaea, the MUD I play all the time. Check it out if you want to get an idea of a high-quality MUD. eMUD will take a lot of ideas from Achaea, mostly because it's such an awesome system, and also because I don't want to have to get used to something else unless it's superior.

~Jonathan

Twisol

Twisol

 

boost::asio

ExplorerMUD is very volatile right now. Nothing's really laid in stone, and things change drastically every other day. Like today, I'm going to be replacing my Thread system with boost::asio.

Off-topic, why is it that everything I make that I think is "good" is sooner or later replaced by something better? *mutter* Worked the same with cConsole, if you remember: I replaced nearly the entire output side of things with three simple iostream manipulators which called Win32 functions. And "the entire output side of things" was pretty complex...

Anyways, I'm working on learning how exactly to use boost::asio for ExplorerMUD. One thing I immediately noticed is connect_pair. I think it's a POSIX-defined function anyways, but I had never heard about it until now anyways. I'd been trying to come up with a simple way to connect two sockets so my commandline and listener threads could communicate. This is massively simple, and I'm very happy. :)

Hopefully boost::asio will simplify some things. I'll still need to create Client objects for each connection and such, but now I don't think it will be so klutzy.

~Jonathan

Twisol

Twisol

 

select()ing on stdin. O_o

Alright, so I've been working on a command line back-end to ExplorerMUD. It's in its own separate thread so I can get input from the person running the server at the same time as other stuff is going on. I can probably merge it into the same thread as the listener now, since I'm select()ing on stdin anyways, but that's beside the point.

The problem: I need to be able to retrieve input from stdin without blocking, and I have to do it without cin because cin just doesn't work like that. If you cin.getline() or cin>>, it waits until the next enter-press even if there's text waiting already, because it wasn't TECHNICALLY waitingblocking for input at the time. It does get the text, but only after you hit enter again, which leaves a newline in there or some other junk, which you'll retrieve next time you enter something... it throws everything off.

Then I found a link that described how to turn off canonical mode on the terminal. It worked, but ugh, no backspace or anything? In fact, the mere attempt at a backspace puts an ugly character in you really don't care about instead of backspacing? There has to be a better way.

Using fcntl to set stdin to O_NONBLOCK, then getting the input char by char with fgetc() worked. So simple, yet so beyond me at first. What a noob! :D

~Jonathan

Twisol

Twisol

 

select()ing on stdin. O_o

Alright, so I've been working on a command line back-end to ExplorerMUD. It's in its own separate thread so I can get input from the person running the server at the same time as other stuff is going on. I can probably merge it into the same thread as the listener now, since I'm select()ing on stdin anyways, but that's beside the point.

The problem: I need to be able to retrieve input from stdin without blocking, and I have to do it without cin because cin just doesn't work like that. If you cin.getline() or cin>>, it waits until the next enter-press even if there's text waiting already, because it wasn't TECHNICALLY waitingblocking for input at the time. It does get the text, but only after you hit enter again, which leaves a newline in there or some other junk, which you'll retrieve next time you enter something... it throws everything off.

Then I found a link that described how to turn off canonical mode on the terminal. It worked, but ugh, no backspace or anything? In fact, the mere attempt at a backspace puts an ugly character in you really don't care about instead of backspacing? There has to be a better way.

Using fcntl to set stdin to O_NONBLOCK, then getting the input char by char with fgetc() worked. So simple, yet so beyond me at first. What a noob! :D

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!