Sign in to follow this  
3lement

[C++] Printing a string character by character.

Recommended Posts

3lement    100
Hi everyone, first time poster here.

Just wanted to say that it seems like you have a great community going here. I'm a complete rookie in C++, and I've been trying to find some good tutorials to practice with. So far, I'm in [b]way[/b] over my head, but day by day it gets less confusing, and that's a good thing. I decided, though, that the best way to go about learning is to try my hand at making a text-based game from scratch, using only reference sites.

I recently stumbled across [url="http://cboard.cprogramming.com/cplusplus-programming/56398-printing-string-time-delay.html"]this forum post[/url] describing how to print out a string, character by character, using iterators. Full disclosure: I haven't reached iterators in my tutorials yet.

Code follows:

[code]// builder.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#include <string>
#include <windows.h>

int main()
{
typedef std::string::const_iterator iter;

std::string msg ( "This is a message" );
iter begin = msg.begin();
iter end = msg.end();

for ( iter it = begin; it != end; ++it ) {
std::cout.put ( *it );
Sleep (75);
}

std::cout<<std::endl;
}[/code]


This is [i]perfect[/i]. Exactly the right speed, exactly what I wanted it to do. The only problem is that it uses a static value for the string ("This is a message"), whereas I'd like my entire (text-based) game to be displayed with this scrolling effect. The idea is that I include the above code in a separate header file, and call to the function whenever text needs to be displayed, thereby creating the desired effect for all the text in the game (except menus, which will have their own header file).

I'm having a really hard time trying to convert the function from static input to dynamic input; any ideas how I might get this done?

Thanks in advance for the patience, I still don't quite know my elbow from my ass.

Share this post


Link to post
Share on other sites
SiCrane    11839
Well you're 90% of the way there, just move your existing code into a separate function and pass the msg as a parameter.
[code]
void slow_type(const std::string & msg) {
typedef std::string::const_iterator iter;

iter begin = msg.begin();
iter end = msg.end();

for ( iter it = begin; it != end; ++it ) {
std::cout.put ( *it );
Sleep (75);
}

std::cout<<std::endl;
}
[/code]

Share this post


Link to post
Share on other sites
3lement    100
Ahh, that must be the 'thinking outside the box' people keep raving on and on about.

Worked perfectly with a forward declaration. Thanks so very much. And if it's alright with your community, I might periodically show the work on my game for suggestions on optimization. ^^

Share this post


Link to post
Share on other sites
3lement    100
Hi guys, quick bump on this, here's the code for my main menu, with custom commands:

commands.h

[code]#include "stdafx.h"
#include <string>
#include "statUI.h"

string Command;
void CmdPrompt();


void NewGame();
void Credits();
int Menu;
void CmdPrompt()
{
if (Command=="/r")
Menu = 0;
if (Command=="N"||"n")
Menu = 1;
if (Command=="C"||"c")
Menu = 3;


switch(Menu){
case 0:
statUI();
break;
case 1:
NewGame();
break;
case 3:
Credits();
break;
}
_getch();
}[/code]


And here are the contents of StatUI, #included above:

[code]#include <iostream>
#include <conio.h>

using namespace std;
int Gold;


void statUI()
{
system("cls");
cout << "\n\tGold: " << Gold << "\t\t\t\t\tWinter, Year 1" << endl;
cout << "\t-------------------------------------------------------" << endl;
_getch();
}[/code]


And finally, the main .cpp file with all the #includes:

[code]// builder.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "commands.h"
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <Windows.h>
#include "sType.h"
#include "intro.h"
#include "NewGame.h"
#include "Credits.h"

void Splash();

int main()
{
Splash();
_getch();
return 0;
}[/code]


I know the code is messy, I'm sorry. It's basically all patchwork. I'm more concerned with actually building something, and figuring it out as I go.

So the problem here is, when I run the program, everything launches fine, except no matter what I choose, it always executes the Credits(); function. This happened after implementing the switch(Main) function in commands.h. Previously, I had been using an if/else statement, but it also had the problem of only executing the NewGame(); function.

Any assistance would be greatly appreciated.

Share this post


Link to post
Share on other sites
Serapth    6671
[color="#000088"]for[/color] [color="#666600"]([/color] iter it [color="#666600"]=[/color] [color="#000088"]begin[/color][color="#666600"];[/color] it [color="#666600"]!=[/color] [color="#000088"]end[/color][color="#666600"];[/color] [color="#666600"]++[/color]it [color="#666600"])



Why are you starting on the second character?[/color]

Share this post


Link to post
Share on other sites
Rattrap    3385
[quote name='Serapth' timestamp='1310579365' post='4834922']
[color="#000088"]for[/color] [color="#666600"]([/color] iter it [color="#666600"]=[/color] [color="#000088"]begin[/color][color="#666600"];[/color] it [color="#666600"]!=[/color] [color="#000088"]end[/color][color="#666600"];[/color] [color="#666600"]++[/color]it [color="#666600"])



Why are you starting on the second character?[/color]
[/quote]

Why do you think it would start on the second character?

begin seems to be initialized as .begin(), which should point to the first character.

Share this post


Link to post
Share on other sites
Serapth    6671
[quote name='Rattrap' timestamp='1310579565' post='4834925']
[quote name='Serapth' timestamp='1310579365' post='4834922']
[color="#000088"]for[/color] [color="#666600"]([/color] iter it [color="#666600"]=[/color] [color="#000088"]begin[/color][color="#666600"];[/color] it [color="#666600"]!=[/color] [color="#000088"]end[/color][color="#666600"];[/color] [color="#666600"]++[/color]it [color="#666600"])



Why are you starting on the second character?[/color]
[/quote]

Why do you think it would start on the second character?

begin seems to be initialized as .begin(), which should point to the first character.
[/quote]

Brain fart, ignore me.

Share this post


Link to post
Share on other sites
Ph4tM4N    108
I'm going to jump in and suggest that you might want to create a second function that also lets you specify the sleep duration, in case you ever want to do it a lot faster or slower. Something like this:

[code]void slow_type(const std::string & msg) {
variable_type(msg, 75);
}[/code]

[code]void variable_type(const std::string & msg, long sleepDuration) {
typedef std::string::const_iterator iter;

iter begin = msg.begin();
iter end = msg.end();

for ( iter it = begin; it != end; ++it ) {
std::cout.put ( *it );
Sleep (sleepDuration);
}

std::cout<<std::endl;
}[/code]

That way game over could frustratingly type out across the screen as slow as possible, while effects or whatever could flash out relatively fast (but not so fast as to appear instant). Or not.

Share this post


Link to post
Share on other sites
3lement    100
[quote name='SkoobyD00' timestamp='1310608489' post='4835087']
I'm going to jump in and suggest that you might want to create a second function that also lets you specify the sleep duration, in case you ever want to do it a lot faster or slower.
[/quote]

Much obliged, I actually have something similar running now.

Another update: work is coming along splendidly, and my interest/motivation for completing this project are quite high. I'm currently stuck on this problem however:

I'm trying to pass the value of the int Profile to the function NewGame(). The idea is that while Profile = 0 (new savegame), the NewGame() function will open up a Savegame menu, and as soon as it's done, will return a value of Profile = 1, allowing the function to progress.

[code]void Intro()
{
int Profile;
Profile = 0;
system("cls");
cout << "\n\t\t\t\t\t\t";
Sleep(3500);
sType("...Where the fuck am I?");
Sleep(5000);
system("cls");
cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t";
sType("Does it really matter?");
Sleep(3500);
sType("\n\n\tThis place can be whatever you want it to be.");
Sleep(6000);
system("cls");
cout << "\n\n\n\n\n\n\n\n\n\n\t\t\t\t";
Sleep(3500);
Gears();
NewGame(Profile);
}[/code]


[code]void NewGame(int Profile)
{
while (Profile = 0)
{
void NewSaveScreen();
NewSaveScreen();
}
system("cls");
cout << "\n\n\t";
Sleep(3500);
sType("> Welcome to Gears. Would you like to read the tutorial?");
cin >> TutReq;
if (TutReq=="Y"||TutReq=="y")
{
Tutorial();
}
else
Beginning();
}[/code]


You might see something I don't here; for some reason, the program will jump over the "while" statement (tried using if/else as well) and go straight to system("cls") in the NewGame() function. I tried using cout to determine the value of Profile both before and after being passed off from the first function to the second, and both values are 0 as they should be.

Any ideas?

Share this post


Link to post
Share on other sites
taliesinnz    231
[quote name='3lement' timestamp='1310777468' post='4835855']
[quote name='SkoobyD00' timestamp='1310608489' post='4835087']
I'm going to jump in and suggest that you might want to create a second function that also lets you specify the sleep duration, in case you ever want to do it a lot faster or slower.
[/quote]

Much obliged, I actually have something similar running now.

Another update: work is coming along splendidly, and my interest/motivation for completing this project are quite high. I'm currently stuck on this problem however:

I'm trying to pass the value of the int Profile to the function NewGame(). The idea is that while Profile = 0 (new savegame), the NewGame() function will open up a Savegame menu, and as soon as it's done, will return a value of Profile = 1, allowing the function to progress.

[code]void Intro()
{
int Profile;
Profile = 0;
system("cls");
cout << "\n\t\t\t\t\t\t";
Sleep(3500);
sType("...Where the fuck am I?");
Sleep(5000);
system("cls");
cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t";
sType("Does it really matter?");
Sleep(3500);
sType("\n\n\tThis place can be whatever you want it to be.");
Sleep(6000);
system("cls");
cout << "\n\n\n\n\n\n\n\n\n\n\t\t\t\t";
Sleep(3500);
Gears();
NewGame(Profile);
}[/code]


[code]void NewGame(int Profile)
{
while (Profile = 0)
{
void NewSaveScreen();
NewSaveScreen();
}
system("cls");
cout << "\n\n\t";
Sleep(3500);
sType("> Welcome to Gears. Would you like to read the tutorial?");
cin >> TutReq;
if (TutReq=="Y"||TutReq=="y")
{
Tutorial();
}
else
Beginning();
}[/code]


You might see something I don't here; for some reason, the program will jump over the "while" statement (tried using if/else as well) and go straight to system("cls") in the NewGame() function. I tried using cout to determine the value of Profile both before and after being passed off from the first function to the second, and both values are 0 as they should be.

Any ideas?
[/quote]

Your problem in in the line [i]while (Profile = 0)[/i] what this does is it assigns the value of 0 to profile. What you need to do is change it to[i] while( Profile == 0 )[/i]. == is used to compare values in c++

Good Luck
Taliesin

Share this post


Link to post
Share on other sites
3lement    100
I seem to have a big problem with operators, huh? Thanks for the quick response, it's always frustrating to struggle with something for a whole day and find out it has such a simple solution.

Share this post


Link to post
Share on other sites
iMalc    2466
Turn your compiler warning levels up. The compiler should warn you about assignment within conditional expresion in this case.

Share this post


Link to post
Share on other sites
3lement    100
Hello again, O masters of all things code-y.

Ran into another problem. I've essentially got my menu system up and running, with a slight error. My program will take input from the user, convert the input to a number which is then assigned to a Menu integer. The Menu header reads this integer, and writes the menu to the screen when called.

However, for some reason, the menu is stuck on "Command List". I've tried switching the sent integer value to Menu = 7; and doing MenuDisplay(Menu), but that doesn't seem to work either.

commands.h:

[code]void CmdSel()
{
if (Command=="M"||Command=="m")
Menu = 0;
else if (Command=="N"||Command=="n")
Menu = 1;
else if (Command=="L"||Command=="l")
Menu = 2;
else if (Command=="C"||Command=="c")
Menu = 3;
else if (Command=="/i")
Menu = 7;
else if (Command=="/c")
Menu = 8;
else
{
sType("\tInvalid key selection. Please choose again.\n");
CmdPrompt();
}


switch(Menu){
case 0:
Splash();
break;
case 1:
Beginning();
break;
case 2:
LoadGame();
break;
case 3:
Credits();
break;
case 7:
Inventory();
case 8:
CmdMenu();
break;
}
_getch();
}

void CmdPrompt()
{
cout << "\tFor help with commands, type /c" << endl;
sType("\n\t> ");
cin >> Command;
CmdSel();
}

void CmdMenu()
{
MenuDisplay(8);
sType("\n\t\t(M)\t\t\tMain Menu");
sType("\n\n\t\t(/c)\t\t\tCommand List");
sType("\n\n\t\t(/r)\t\t\tResource Menu");
sType("\n\n\t\t(/i)\t\t\tInventory Menu");
sType("\n\n\t\t(/b)\t\t\tBuilding Menu");
sType("\n\n\t\t(/m)\t\t\tMining Actions");
sType("\n\n\t\t(N)\t\t\tNew Game (Main Menu only)");
sType("\n\n\t\t(L)\t\t\tLoad Game");
sType("\n\n\t\t(S)\t\t\tSave Game");
cout << "\n\t-------------------------------------------------------" << endl;
sType("\n\t Please select a command:");
sType("\n\t> ");
cin >> Command;
CmdSel();
}[/code]


the MenuDisplay() function:

[code]

string MenuHead;

void MenuDisplay(int Menu)
{
switch(Menu)
{
case 1:
MenuHead = "Menu - New Game";
case 7:
MenuHead = "Menu - Inventory";
case 8:
MenuHead = "Menu - Command list";
}


system("cls");
cout << "\n\t " << MenuHead << endl;
cout << "\t-------------------------------------------------------" << endl;
}[/code]


And finally, the call to menu printing function:

[code]void Inventory()
{
MenuDisplay(7);
sType("\n\n\t\tPickaxe:\t\t[") ;
if (HavePickaxe==1)
sType("x]");
else
sType(" ]");
_getch();
}[/code]


So, as mentioned above, when the user gets to the Splash() page, they can input "/i" to access the Inventory screen. The command does indeed lead to the right screen, but the menu Header is stuck on "Menu - Command List".

Any idea why this is happening?

Share this post


Link to post
Share on other sites
ApochPiQ    23003
You need to put a break; after each chunk of code in a switch/case. Otherwise, once the code matches a case, it just keeps on running until it hits the end of the switch. A break informs the compiler that you want each case to be isolated without what is known as "falling through" to subsequent cases.

Share this post


Link to post
Share on other sites
3lement    100
Works perfectly... live and learn.

By the by, is it bothersome that I keep posting in the same thread? I figure it'd be bad etiquette to make a new one for every little problem I run into.

Thanks again for being so helpful, guys. I definitely feel the love.

Share this post


Link to post
Share on other sites
ApochPiQ    23003
It's cool either way :-) The benefit to starting new threads is that it helps people jump in since they don't have to wade through the history to see what's already working - they can go straight to the latest problem.

Up to you, though, really. Just use common sense :-)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this