Intel sponsors gamedev.net search:   
Adventures in Text-modeBy Twisol      
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


Saturday, April 26, 2008
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!


Comments: 0 - Leave a Comment

Link


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!

Comments: 0 - Leave a Comment

Link



Monday, April 21, 2008

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:

  1. Finish the basic look of the HUD.

  2. Store character and color values in files

  3. Create some walls and the player sprite

  4. 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.

Comments: 0 - Leave a Comment

Link



Saturday, April 19, 2008
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.

Comments: 1 - Leave a Comment

Link


Heh, yeah, I feel like a squib right now.*

I've been feeeling a little, eh... stagnant with my programming lately, mostly because I haven't been able to properly complete a project. ((Yes, I realize many of you haven't either :D)) So I bought the GameTutorials set of tutorials... so far I think I've made a worthwhile investment.

I ran through the early C++ tutorials really fast just to make sure I knew what I needed, and I eventually got to some Win32 console stuff, like what I had been doing with cConsole before. One tutorial that caught my eye was "Color Text"... I glanced over it, and behold, text coloring in the console that was far simpler than what cConsole attempted. I really was floundering back there, ugh.

So I ran through the tutorial code, tweaked it, and got rid of the positioning code; I didn't feel I needed it at that point. What I got worked well enough: two functions, ColorPrint and ColorPrintln, that took a text string and a color value. I found I was passing the same color value repeatedly, and besides that it looked really monotonous and klutzy. So I tried something I haven't tried before: I made an iostream manipulator, to use with std::cout.

At first I had the most basic of manips:
class color
{
    private:
        ConsoleColor myColor; // This is just an enum of colors I made.
    public:
        color(ConsoleColor theColor)
            : myColor(theColor)
        {}

        void operator()()
        {
            HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
            SetConsoleTextAttribute(hOut, myColor);
        }
};

ostream& operator<<(ostream& out, color theColor)
{
    theColor();
    return out;
}




I liked this solution a lot better than the functions I had made before. All you needed to do was creat the manip and pass it to cout. Like most manipulators that I've seen, all you need to do is this:

cout << color(CC_CYAN) << "Hello, Cyan!\n";


Easy and intuitive, especially because you're using cout there instead of through a function. A few slight gripes I have are that the manipulator does not actually change the state of cout... it changes the attributes of the console itself. This will be important later! For this reason, the operator() doesn't require any parameters, nor does it return anything. The operator<< is then made to call the function object and return the ostream... and nothing at all was done with that ostream. It seems like a waste, but it's the only way to make the manip work with cout! In that regard, it's a little like the differences between overloading the ++ operators; you have an unused variable to differentiate.

Well, me being me, that wasn't enough. I took the positioning code from before and made it into its own manip. All it does is set where the console caret is... thus, again, it does nothing to the ostream itself, only the console. Again, this will be important later!

Further, foreground text coloring isn't the only coloring you can do with the console; you can also color the background of the character cells. I thus renamed the color manip into 'forecolor', and created the 'backcolor' manip, which looked exactly like forecolor, but bitshifted the color value << 4 (because internally the background color is placed at 0xF0, where foreground is 0x0F, in the same mask).

The backcolor manip worked just as well as the forecolor manip did... except that they didn't take eachother into account. Do you see the problem? If the console text attributes already had a foreground, if I called the backcolor manip, it replaced the entire mask with the lone background color. Obviously, that's not good, especially because color values are not the only values held in that mask.

In short (yeah, like anything about this post was short!), I called GetConsoleScreenBufferInfo() for the screen buffer info struct, took the attributes mask out (which is of the WORD type), and did some binary ORs and ANDs. The formula I used to retain the original mask, but replace the value I wanted with the forecolor, is ((theMask & 0xFFF0) | myColor). I AND out the part I want to remove, but retain the rest, and OR in the new value! This fixed my mask problem.

Here's the code for the color manips, with inheritance included. Feel free to use it!

CONCOL.H (CONsole COLor)
#include <iostream>
#include <windows.h>

enum ConsoleColor { CC_BLACK = 0, CC_BLUE,    CC_GREEN,  CC_CYAN,
                    CC_RED,       CC_PURPLE,  CC_YELLOW, CC_WHITE,
                    CCI_BLUE = 9, CCI_GREEN,  CCI_CYAN,  CCI_RED,
                    CCI_PURPLE,   CCI_YELLOW, CCI_WHITE};

class color
{
    protected:
        ConsoleColor myColor;
    public:
        color(ConsoleColor theColor);
        virtual void operator()() = 0;
};

class forecolor : public color
{
    public:
        forecolor(ConsoleColor theColor);
        void operator()();
};

class backcolor : public color
{
    public:
        backcolor(ConsoleColor theColor);
        void operator()();
};

std::ostream& operator<<(std::ostream &out, color &theColor);





CONCOL.CPP
#include "concol.h"

color::color(ConsoleColor theColor)
    : myColor(theColor)
{}

forecolor::forecolor(ConsoleColor theColor)
    : color(theColor)
{}

backcolor::backcolor(ConsoleColor theColor)
    : color(theColor)
{}

void forecolor::operator()()
{
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_SCREEN_BUFFER_INFO* csbi = new CONSOLE_SCREEN_BUFFER_INFO;
    GetConsoleScreenBufferInfo(hOut, csbi);

    SetConsoleTextAttribute(hOut, ((csbi->wAttributes & 0xFFF0) | myColor));
    delete csbi;
}

void backcolor::operator()()
{
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_SCREEN_BUFFER_INFO* csbi = new CONSOLE_SCREEN_BUFFER_INFO;
    GetConsoleScreenBufferInfo(hOut, csbi);

    SetConsoleTextAttribute(hOut, ((csbi->wAttributes & 0xFF0F) | (myColor << 4)));
    delete csbi;
}

std::ostream& operator<<(std::ostream &out, color &theColor)
{
    theColor();
    return out;
}




There it is. Now, remember how the manips affect the console, NOT cout? This is important, and I'll explain why. When you use one of the color manips, for example, it sets the state of the console to put characters in that color scheme from that point on. This includes input typed via cin. Wow, who would have guessed? Ah, well, like I said, the color manips don't touch cout anyways. They're not exactly your usual manips. This means that you can have the user enter input in a different color. That's pretty neat, isn't it? It works the same for the position manip, even though I haven't put the code up here. Once you set the caret position, cout and cin work from there.

So... pointers, ideas, criticism, and of course colored input are all welcome!

~Jonathan

EDIT: And of course, I forgot to mention! Because both manips are derived from the virtual class 'color', only one operator>> is needed, because it can take a reference to an object of type color. Handy!



* Oh yeah, about the squib comment. In Harry Potter, Mr. Filch the caretaker is a Squib, meaning a wizard-born who's barely got a drop of magic in their blood. A programmer squib, thus, should be obvious. To take the analogy further, compare GameTutorials to Kwikspell, and there you have it.

Comments: 0 - Leave a Comment

Link


All times are ET (US)

 
S
M
T
W
T
F
S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
20
22
23
24
25
27
28
29
30

OPTIONS
Track this Journal

 RSS 

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