BlogProfit.com – Blogging Tutorials – 75% Commissions
The best collection of blogging, social media, email marketing and SEO video tutorials ever made.
BlogProfit.com – Blogging Tutorials – 75% Commissions
DOWNLOAD THE DEMO AND SOURCE CODE FOR WINDOWS
DOWNLOAD THE DEMO AND SOURCE CODE FOR LINUX
RETURN TO THE TUTORIAL INDEX
In the last tutorial we used a slightly modified version of a DotScene loader to load and display a 3D terrain. Now we will add a controllable player to the scene, and have it fly over the terrain.
The terrain we have loaded is not infinite – it has definite edges that we don’t want to be seen in the final game. To avoid this we need to start the camera in a position where it can not see the edges of the terrain while looking straight down, and then stop the camera from scrolling past the end of the terrain.
The starting position of the camera is determined by the XML scene file. In this demo we have started the camera at [125, 225, 1150]. This places it 100 units from the end of the level, which is 1250 units long. At a height of 225 and looking straight down this means the camera can not see the edges of the level.
The GameLevel class will scroll the player and the camera over the terrain along the z axis until they reach 100 units (the difference between the length of the terrain and the cameras initial position on the z axis). In this way the camera will stop scrolling at a point where the end of the terrain is also just out of sight.
These calculations require that the GameLevel class know the length of the terrain (the PageWorldZ attribute in the XML file). This value is not easily accessible from the SceneManager itself, so the DotSceneLoader is modified slightly to pass this value to the GameLevel singleton directly.
void DotSceneLoader::processTerrain(TiXmlElement *XMLNode)
{
// …
String pageWorldZ = getAttrib(XMLNode, “PageWorldZ”);
if (pageWorldZ.size() != 0)
{
terrainConfig += “PageWorldZ=”;
terrainConfig += pageWorldZ;
terrainConfig += “\n”;
GAMELEVEL.SetLevelLength(Ogre::StringConverter::parseReal(pageWorldZ));
}
// …
}
Another change is that the DotSceneLoader now references the SceneManager held by the GameLevel singleton instead of maintaining it’s own internal pointer. If you look through the DotSceneLoader class you will see that the GameLevel GetSceneManager function is used when access to the Scene Manager is required.
The GameLevel class gets a new function called SetLevelLength which stored the length of the level in a new varaible called levelLength.The cameraStartZ variable is added to store the initial z position of the camera. The last new variable is a Scene Node called playerSceneNode, which the players ship model will be attached to.
GameLevel.h
/*
* GameLevel.h
*
* Created on: 18/12/2009
* Author: Matthew Casperson
* Email: matthewcasperson@gmail.com
* Website: http://www.brighthub.com/hubfolio/matthew-casperson.aspx
*/
#ifndef GAMELEVEL_H_
#define GAMELEVEL_H_
#include “Ogre.h”
#include “PersistentFrameListener.h”
#define GAMELEVEL GameLevel::Instance()
class GameLevel :
public PersistentFrameListener
{
public:
~GameLevel();
static GameLevel& Instance()
{
static GameLevel instance;
return instance
}
void Startup(std::string scene);
void Shutdown();
bool FrameStarted(const FrameEvent& evt);
SceneManager* GetSceneManager() const {return sceneManager;}
SceneNode* GetPlayerSceneNode() const {return playerSceneNode}
void SetLevelLength(float length) {levelLength = length;}
protected:
GameLevel();
void InitialiseVariables();
SceneManager* sceneManager;
Camera* camera;
Viewport* viewport;
SceneNode* playerSceneNode;
float levelLength;
float cameraStartZ;
};
#endif /* GAMELEVEL_H_ */
GameLevel.cpp
The cameraStartZ variable is set to the cameras z position after the scene has been loaded in the GameLevel Startup function. The new Player class is also initialised by calling its Startup function.
void GameLevel::Startup(std::string scene)
{
PersistentFrameListener::Startup();
sceneManager = ENGINEMANAGER.GetRoot()->createSceneManager(“TerrainSceneManager”);
camera = sceneManager->createCamera(“Camera”);
viewport = ENGINEMANAGER.GetRenderWindow()->addViewport(camera);
std::auto_ptr sceneLoader(new DotSceneLoader());
sceneLoader->parseDotScene(scene, LEVEL_GROUP_NAME);
cameraStartZ = camera->getPosition().z;
playerSceneNode = sceneManager->getRootSceneNode()->createChildSceneNode();
playerSceneNode->setPosition(camera->getPosition().x, camera->getPosition().y – PLAYER_Y, camera->getPosition().z);
PLAYER.Startup()
}
The Players Shutdown function is then called in the GameLevel Shutdown function.
void GameLevel::Shutdown()
{
PLAYER.Shutdown();
if (playerSceneNode != NULL) sceneManager->getRootSceneNode()->removeAndDestroyChild(playerSceneNode->getName());
if (viewport != NULL) ENGINEMANAGER.GetRenderWindow()->removeViewport(viewport->getZOrder());
if (sceneManager != NULL) ENGINEMANAGER.GetRoot()->destroySceneManager(sceneManager);
PersistentFrameListener::Shutdown();
InitialiseVariables();
}
The FrameStarted function, which is called once per frame, is used to scroll the player (by moving the playerSceneNode to which the players mesh is attached) and camera over the terrain, stopping when the camera is as far from the end of the terrain as it was from the beginning when the scene was loaded.
bool GameLevel::FrameStarted(const FrameEvent& evt)
{
if (playerSceneNode->getPosition().z > this->levelLength – this->cameraStartZ)
{
float translateDist = SCROLL_SPEED * evt.timeSinceLastFrame;
float distToEnd = playerSceneNode->getPosition().z – (this->levelLength – this->cameraStartZ);
playerSceneNode->translate(-1 * Vector3(0, 0, translateDist>distToEnd?distToEnd:translateDist));
}
camera->setPosition(playerSceneNode->getPosition() + Vector3(0, PLAYER_Y, 0));
return true;
}
The Player class represents the players ship on the screen.
Player.h
/*
* Player.h
*
* Created on: 21/12/2009
* Author: Matthew Casperson
* Email: matthewcasperson@gmail.com
* Website: http://www.brighthub.com/hubfolio/matthew-casperson.aspx
*/
#ifndef PLAYER_H_
#define PLAYER_H_
#include “PersistentFrameListener.h”
#define PLAYER Player::Instance()
class Player :
public PersistentFrameListener
{
public:
~Player();
static Player& Instance()
{
static Player instance;
return instance;
}
void Startup();
void Shutdown();
bool FrameStarted(const FrameEvent& evt);
protected:
Player()
void InitialiseVariables();
void KeepPlayerOnScreen();
Entity* playerMesh;
SceneNode* playerSceneNode;
};
#endif
Player.cpp
The PLAYER_MESH constant defines the mesh that represents the player.
The MOUSE_SPEED constant defines how quickly the player moves with the mouse.
The SCREEN_X and SCREEN_Z constants define the bounds that the player can move in on the screen.
#include “OgreEngineManager.h”
#include “Player.h”
#include “GameLevel.h”
static const char* PLAYER_MESH = “player.mesh”;
static const float MOUSE_SPEED = 0.5f;
static const float SCREEN_X = 75.0f;
static const float SCREEN_Z = 55.0f;
Player::Player()
{
InitialiseVariables();
}
Player::~Player()
{
}
void Player::InitialiseVariables()
{
playerMesh = NULL;
playerSceneNode = NULL
}
The Startup function loads the mesh, which is called an Entity in Ogre.
void Player::Startup()
{
PersistentFrameListener::Startup();
playerMesh = GAMELEVEL.GetSceneManager()->createEntity(“Player”, PLAYER_MESH);
We then create a child scene node from the player scene node that was created by the GameLevel class. This is because you can not position an Entity directly – it has to be attached to a SceneNode, and then the SceneNode can be positioned.
playerSceneNode = GAMELEVEL.GetPlayerSceneNode()->createChildSceneNode();
The Entity is then attached to the SceneNode.
playerSceneNode->attachObject(playerMesh);
Finally, the SceneNode is rotated so the players ship faces the correct way.
playerSceneNode->rotate(Vector3(0, 1, 0), Angle(180));
}
The Shutdown function does the reverse of the Startup function, detaching and destroying the Entity and SceneNode.
void Player::Shutdown()
{
playerSceneNode->detachAllObjects();
GAMELEVEL.GetPlayerSceneNode()->removeAndDestroyChild(playerSceneNode->getName());
GAMELEVEL.GetSceneManager()->destroyEntity(playerMesh);
InitialiseVariables()
PersistentFrameListener::Shutdown();
}
The FrameStarted function is used to move the player with the mouse, and then calls the KeepPlayerOnScreen function to make sure the player does not move off the screen.
bool Player::FrameStarted(const FrameEvent& evt)
{
playerSceneNode->translate(
ENGINEMANAGER.GetMouse()->getMouseState().X.rel * MOUSE_SPEED,
0,
ENGINEMANAGER.GetMouse()->getMouseState().Y.rel * MOUSE_SPEED);
KeepPlayerOnScreen();
return true;
}
The KeepPlayerOnScreen function uses the constants SCREEN_X and SCREEN_Z to keep the player on the screen.
void Player::KeepPlayerOnScreen()
{
Vector3 newPosition = playerSceneNode->getPosition();
if (newPosition.x > SCREEN_X)
newPosition.x = SCREEN_X;
else if (newPosition.x SCREEN_Z)
newPosition.z = SCREEN_Z;
else if (newPosition.z setPosition(newPosition);
}
The end results of these changes is that a ship that can be controlled by the mouse is added to the scene. The ship and the camera then both scroll along the terrain until they reach the end of the level. Although the player can not do anything at this point except move around, we do now have something that looks
July 4th, 2011 on 2:11 am
so. are there any more guides?
July 4th, 2011 on 2:42 am
Lol hundred thousands of people saw the first video but only 8 stayed to the end.
I am at 10 atm :p nice tut.
July 4th, 2011 on 3:18 am
I would like to recommend an excellent reading to complement this tutorial
c++ the absolute begginer’s guide ( Herbert Schildt )
helped me a lot in science college.
July 4th, 2011 on 3:27 am
@Aldeni1551
151,669 gave up, the last 8 watched this 1000 times lol
July 4th, 2011 on 4:25 am
@Aldeni1551 Yup, thats what I was thinking. But the thing is, everyone would love to be able to know C++. But learning it is really, really fucking hard – not everyone can do it. But it has been so much easier with these tutorials – Thanks antiRTFM, you’re a legend!
July 4th, 2011 on 5:23 am
The first video in this series has 151,677 views. The last one has 8,371 views.
How sad that 143,306 people gave up…
July 4th, 2011 on 6:07 am
u should make more videos if u have time. imo ur one of the best on youtube for this
July 4th, 2011 on 6:54 am
D: I’m just here to see what it is like to succeed.
I must succeed.
July 4th, 2011 on 7:47 am
i can’t believe this is the last video… Well done, you helped me out a lot
July 4th, 2011 on 7:55 am
@Z3r0XoL use header files to get functions from the other c++ files
July 4th, 2011 on 7:56 am
Ty for those guides =D ur the man!
July 4th, 2011 on 8:40 am
i like how you tell what you will be teaching in vid description
July 4th, 2011 on 8:51 am
do u have a vid where u r showing how it looks?
July 4th, 2011 on 9:19 am
@KDEfan97 I wrote a trainer for GTAIV after about 6 months programming.
A full trainer with an in game Text interface.
July 4th, 2011 on 10:04 am
@KDEfan97 “I know this because I am what they call the master of C++. ”
hmm, a C++ guru eh? What have you programmed lately?
July 4th, 2011 on 10:07 am
i need a tutorial for file handling with multiple .cpp files
July 4th, 2011 on 10:58 am
thanks for all your tutorials, especially for the new tutorials…
July 4th, 2011 on 11:40 am
if the individual who wish to learn C++ is stupid dull it requaire a year experiance and study , if the person who study C++ is clever or remmaber stuff easyly then it took a month to become expert remamber this what elder call the extand of human brain capability to learn stuff
July 4th, 2011 on 11:53 am
I see I see mah mastha
so u dam pro shet?
July 4th, 2011 on 12:30 pm
That is because your friend doesn’t understand the basic yet important concepts of C++. It is impossible to learn the whole language within a few months.
You could read 10 dozen books on C++ and you would still not be an expert. It requires years of experience to make real world programs.
Hacking in C++ requires years of experience, not months. I know this because I am what they call the master of C++.
July 4th, 2011 on 1:26 pm
nah mah friend did it in some months..
July 4th, 2011 on 1:48 pm
It would require years of experience with C++ to be able to hack a thing such as a game.
July 4th, 2011 on 1:57 pm
Thanks for the new tutorials!!!!!
July 4th, 2011 on 2:53 pm
yes new ones , keep it up man.
July 4th, 2011 on 2:54 pm
very good english by the way
July 4th, 2011 on 3:53 pm
I have a question wich I think will help n00bs like me:
Can I put a character like % for the name of variable?
Like : char %;
July 4th, 2011 on 4:28 pm
in this video you show the int limit numbers, like what the max number is. How do you get that? is there a key you push to have the number automatically show up? great videos by the way.
July 4th, 2011 on 4:34 pm
yes really beter than readx very interestx thanks alot
July 4th, 2011 on 5:25 pm
Oh god you should teach in schools your tutorials are so helpful!
July 4th, 2011 on 6:22 pm
for live help
#cpphelp on irc.mibbit.net, webclient at mibbit.com :3
July 4th, 2011 on 6:42 pm
@TyRATnt C# may fit for big applications aswell. I’m not sure about how good performance it has compared to C++. But C# only works on windows.
July 4th, 2011 on 7:00 pm
@antiHUMANDesigns I agree, though the developer’s that work in my mother’s company make a very complex program called “Patrell” or something like that. It’s a 3D modeling tool for oil. It was made in C# I believe.
July 4th, 2011 on 7:19 pm
@TyRATnt Ye, I’m 29 now. Well, yes, C++ might be the most powerful language, but it is also designed for very large code projects, not small ones. It takes more code to do anything in C++, but it also keeps the code very safe and organized, which is what you need for big or huge projects. Making Notepad in C++ is kind of pointless when languages such as C# or Java would do it faster.
July 4th, 2011 on 7:22 pm
@antiHUMANDesigns Wow, that’s a long time. I’m now fifteen, and started programming since I was fourteen. I started with VB6, as you can see in my video’s. But for about 1-2 month’s I’ve been learning C++, since it’s one of the most powerful language’s out there. If anything, it’s the most powerful.
July 4th, 2011 on 7:59 pm
@TyRATnt Heheh… trolls.
Ye, I started when I as 11, actually. Only been doing C++ for about 8-10 years, though.
July 4th, 2011 on 8:56 pm
@antiHUMANDesigns Lol, to be honest I’m trolling. Wow, that’s a long time to be programming. I’ve only been programming for about one year.
July 4th, 2011 on 9:02 pm
@TyRATnt I hope you’re being serious. I didn’t mean to bash on you, so I do apologize if I did. Well, I’ve been programming for about 18 years. Not sure how my grammar’s bad, but I’m a swede so I guess I woulnd’t know.
July 4th, 2011 on 9:43 pm
C̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟̟͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗+̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖̖͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗͗̎̎̎̎̎̎̎̎̎+̖̖̖̖̖̖̖̖̎̎̎̎̎̎̎̎ Here’s another.
July 4th, 2011 on 10:20 pm
Here’s another example. C̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑+̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑+̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑͑̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒̒
July 4th, 2011 on 10:59 pm
@antiHUMANDesigns EDIT: Also, sorry for Unicode spamming your ass. Man, that’s a nice Unicode encrypter I made. E̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅x̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅a̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅m̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅p̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅l̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅e̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̘̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅
July 4th, 2011 on 11:01 pm
@antiHUMANDesigns Oh, actually, I think I learned something too. You seem like an okay coder, your grammar skill’s need to improve though. Sorry, I was attacked by some idiot in the project’s. He said “I’ll slit yo neck and put ma ba ba ba ballz of steel down ur throat so hard, that yo mom will be wondaiin why u wouldn’t sell me battletoadz you sick son of a bitch”.
July 4th, 2011 on 11:44 pm
@TyRATnt That’s what you get for trying to help and clarify for people. Some people may actually understand that I was helping.
July 5th, 2011 on 12:14 am
To everyone who thinks antiHUMANDesigns is a faggot who thinks he’s cool, go to his channel, and post this “antiHUMANDesigns is a FUCKING S̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑K̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑Ȋ̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑D̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̜̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑̑”
July 5th, 2011 on 12:44 am
@antiHUMANDesigns All you do is trash people’s video’s. You did it to me too, and really no one thinks you’re cool because you “Correct” people’s video’s. Most of the time it’s right. For example. In my video you said “dont uz using namespace std; itz for noobz” That’s how you sound, since your grammar, and your spelling is horrid. My application doesn’t have the variable cout, cin. I DON’T HAVE TO DO IT. GTFO OFF OF YOUTUBE. Who name’s there variable’s after function’s and such anyways?
July 5th, 2011 on 12:58 am
CORRECTION / CLARIFICATION:
A “char” type variable is actually a very short “int”. It does NOT store a character in memory, it stores a normal integer number. Because we call it “char”, we allow the programmer to remember that it is supposed to be used as a value that represents a letter in the ASCII table, but to the computer it is still only a normal integer.
If you add two char variables together, you are adding their ASCII values together.
July 5th, 2011 on 1:21 am
what i do is add // < — this allows text to remember something
such as…
unsigned short int y; // 0 – 65535
unsigned long int z; // 0 – 4294967295
signed short int a; // -32768 – 32767
signed long int b; // -2147483648 – 2147483647
lets say if you are unsure, the // ignores everything after so you can leave the #’s
July 5th, 2011 on 1:26 am
@antiRTFM One time I used a char on an if statement, made it a word. And the if statement (I think it was genders) took any word starting with the same letter, and used it. At first I was creeped out until I used something like burrito O_O.
July 5th, 2011 on 1:31 am
so if I have :
int a = 6.57
it will not round that integer to 7? it will give it the value of 6 even if the decimal is 6.999?
July 5th, 2011 on 1:42 am
why make another line containing the variable ” h = ‘$’; ” when you can just easily write like this ” char h = ‘$’; ” on the first line declaring the char?
July 5th, 2011 on 2:14 am
To long for it to swallow…….
You had this comin to you bud……..
Thats whats SHE SAID