Making Your First Game: Pong
Welcome to the tutorial. This tutorial will be mainly aimed at those who have completed the previous tutorials on this site.
The other tutorials mainly focused on individual parts of lua. This tutorial will walk you through making the game Pong, using what you have learned from previous tutorials.
You can view the complete code for the game HERE

Getting Started
There is a lot of thought that goes in to making even the smallest of games.
One of the most useful things you can do before attempting to code anything is to jot down some things that your game will do, or need to do.
Anything you can think of jot it down. The list doesn't have to be in some certain order.
Any plan is better than no plan.
We are making Pong, so below I will note some things about Pong that we will need to accomplish in our code.

Create 3 images. A ball and 2 paddles
Make the ball start from the center, and move towards a player paddle
Player paddle must be moved vertically using up and down buttons
One paddle will be CPU controlled with simple AI (Artificial Intelligence)
Check for collisions between the ball and paddles
Ball will reverse direction when struck by paddles
Score will be made for player 1 if ball exits screen right
Score will be made for player 2 if ball exits screen left
Display score to the screen
When score is made re-center ball and wait for user input to start round
Declare a winner to the player who scores 10 points first
Should be able to pause the game at any time.

Now, we have a basic understanding of some things that we need to accomplish. Always feel free to go back and add more as you think of different ideas.

Create The Player & Ball Objects:
A good starting point for us will be to create our images for the game so that we have something to see.
We will create these images inside of an array. These arrays will also hold other information about our objects.
Here's our first bit of code.

-- Create Empty Images For Paddles and Ball
Player = {}
Player[1] = { x = 2, y = 50, speed = 2, score = 0, img = Image.createEmpty(16, 64) }
Player[2] = { x = 462 , y = 50, speed = 2.4, score = 0, img = Image.createEmpty(16, 64) }

Ball = { x = 240, y = math.random(60,180), xspeed = -3, yspeed = 3, img = Image.createEmpty(8, 8) }

-- Color The Images We Created
Player[1].img:clear(Color.new(255,128,64))
Player[2].img:clear(Color.new(128,0,64))
Ball.img:clear(Color.new(218,218,218))

Above we've created an array named Player for our two paddles. We have two elements within the Player array, which are 1 and 2. We have stored the x and y values for each paddle, so that we may use these values to properly place and move the paddles.
speed has been given to tell us how fast our paddles can move.
Did you notice that the Player 2 paddle moves faster than Player 1's paddle? Later on this will even out the gameplay a bit since Player 2 will be CPU controlled.
score is set to zero for both players. Later we will increment these as the players score points.
We create an empty image and store it in img. We color these images with a solid color at the bottom of the code.
The ball is created in the same manner basicly.
Notice the ball's y uses the math.random() command. This will cause the ball's y position to start somewhere randomly between 60 and 180. We also give the ball an xspeed and yspeed rather than just one speed since it will move both horizontally and vertically, unlike our paddles which only move vertically.

Starting Our Functions
The majority of our code will be written in functions. We will then call the functions from our main loop as we need them. Since we have already created our paddles and our ball, let's go ahead and make a function that will draw those image we created to the screen. Below is our next piece of code:

-- Create Functions
function drawImages()
screen:blit(Player[1].x,Player[1].y,Player[1].img)
screen:blit(Player[2].x,Player[2].y,Player[2].img)
screen:blit(Ball.x,Ball.y,Ball.img)
end

Now, we have created a function called drawImages()
We will place this in our loop and it will draw our images to the screen.
Notice we are using our table(array) information we created earlier to fill in the blit arguments.
We set up our player and ball x,y, and img info when we created the tables.
Note that all functions we create need to be placed above our main loop code. Try keeping all your function declarations in one area. Add each new function we make under the last one created.

Starting The Main Loop:
We can't do much for testing our game without getting a main loop started. So let's do that now.
We'll start a loop that looks just like the others you've seen in the past tutorials. Inside the loop we will place our drawImages() function so that our images will get drawn to the screen at their proper locations.
Insert the code below underneath all the code we have so far:

while true do
screen:clear()

drawImages()

screen.waitVblankStart()
screen.flip()
end

Go ahead and save and run the program. You should see the paddles and ball there on the screen. Those objects are now getting blitted every single frame to the screen.
Why don't you close and restart the program several times and see if you notice anything unusual...go ahead I'll wait!
In case you didn't catch it, earlier when we created our ball we told our program to place the ball's y position at a random location each time we start the game. Well, with a keen eye you'll notice that it appears at the exact same location each time you run the program.
The fact is randomness on a computer is never really random totally, but in order to make it random at all you will have to seed the random numbers with a command called math.randomseed().
Inside the randomseed command we will pass os.time() as an argument.
Since time is almost always different, this will almost always cause a different result.
So, at the very top of your code file, above everything else put this in:

math.randomseed(os.time())

Now save and run the program again. Exit and restart it a few times, and the ball should now be placed in a different position each time.
Note that no matter how many random commands you use in your program you really only need to seed the entire program one time at the top of your code, and not each time you use a random number.

Moving The Ball:
Now that our images are appearing on screen let's move on to making the ball move.
Before we jump into it let's think about what it needs to do.
The ball will need to move around the screen first of all.
Also, the ball needs to repel or bounce off the top and bottom of the screen.
We know that if the ball moves off the screen either to the left or to the right someone has scored a point.
This and the fact that the ball should bounce off the paddles will wait.
Let's just get it moving around first.
First of all let's add in a table called Resolution to our code. We will use this table to refer to the PSP's screen width and height, which is 480x272.
So, under the code where we colored our images, and before our create functions section add this code:

-- Variables and Tables Resolution = { width = 480, height = 272 } We will need to refer to the PSP's screen width and height later, and now we can do so using Resolution.width and Resolution.height Now on to moving the ball. We will create a function named ballMovement() that will control the ball's movements. In our Pong game the ball has a static speed of 3. But, we will use negative and positive with 3 in order to make the ball go left and right, or up and down. Here's the function. Add this function under your drawImages() function we made earlier.
function ballMovement()
if Ball.y <= 0 then
Ball.yspeed = 3
end
if Ball.y + Ball.img:height() > Resolution.height then
Ball.yspeed = -3
end

Ball.x = Ball.x + Ball.xspeed
Ball.y = Ball.y + Ball.yspeed
end

The two if statements in the code above do not actually make the ball move. These two statements are checking to see if the ball is at the top or bottom boundaries of the screen. If it determines the ball is at either of these it will inverse the ball's yspeed value in order to reverse the ball, or to make it bounce off the screen.
The ball's yspeed is it's vertical speed, while it's xspeed is it's horizontal speed.
Since the top pixel of the screen is zero then we check to see if the top of the ball (Ball.y) is less than or equal to zero.
If it is, then the ball's yspeed get's set to positive 3.
The second if statement looks a bit more complicated.
Here we take the top of the ball's position (Ball.y) and add the height of the ball's image (Ball.img:height() ) to that and check to see if the total of those is greate than the resolution height, which is 272. The reason we add the images height to the ball's position is so that for the bottom of the screen we are checking to see if the bottom of the ball is hitting the bottom of the screen, rather than the top of the image. If we checked only the ball's y position alone, then the ball would slightly exit the screen before bouncing back when it hit the bottom.
If it determines we have hit this area then the ball's yspeed gets set to negative 3.
The last two lines are where we actually change the position of the ball.
We add the ball's xspeed to the ball's y position which will move the ball 3 pixels to the left or to the right.
The same goes for the y of the ball.
If the yspeed is a negative value the ball will move upwards since adding a negative value to a number decreases the value of that number.
With y position the lower the number is the higher up on the screen it is, whereas with x position the lower the number is the more to the left of the screen it is.
Notice we don't change the direction of x with xspeed in this function. The only thing that will change the x direction will be when the ball collides with a paddle, which we'll deal with in a collision function later.

In our Pong game the ball will always start going left at the beginning of our game.
Go ahead and save and run the program. The ball will probably bounce off the bottom of the screen and vanish into negative position infinity. Congratulations, you have a moving Pong ball!

Game States:
All games have functions that do certain things. But the fact is, there are only certain times when certain functions need to be used.
For instance, if you pause a game should the ballMovement() code still be performing? Well, no it shouldn't.
If you're in the middle of playing Pong should your game over code be running? Nope...
If you look in our main loop you'll notice that our functions are getting called every single time the loop performs without question.
That's fine and dandy with what we've got so far, but when a game starts getting a bit more complex you need to implement what's called a state, or game state dealing with games.
A game state can at it's simplest form be a single variable.
What this state will do is tell the program when and when not to perform certain tasks within our games.
In our game we're gonna create a game state variable called...gasp... gamestate.
We will use 3 states to determine what needs to be running in our game: paused, playing, and scored
Underneath your Resolution table you created earlier insert this code:

gamestate = "paused"
white = Color.new(255,255,255)

Now we have created our gamestate and set it's value to "paused" initially. This means our game will start in a paused state.
Right now it doesn't do anything, but it will!
The white color object will be used to print text to the screen in a bit.
You now know that game states can allow you to focus on running only parts of your code that you need at that time, but another important thing to know is that you also need a way to get into the state, as well as out of the state.
You have to tell the program when and how to enter and exit a state.

Our game is starting in a "paused" state that we set with our game state variable earlier.
The function ballMovement() that we have in our loop should not perform while the game is paused.
So, let's prevent it from doing so now. We are going to set the function to only perform if the game is in a state set to "playing".
So, around those two functions in your main loop add this if statement around them so that it looks like the code below:

if gamestate == "playing" then
ballMovement()
end

We left the drawImages() out of the check because it's OK to draw the images while the game is in a paused state, as long as the images aren't being moved. Our drawImages() function doesn't move anything. It only draws to the screen.
If you save and run the program now you'll no longer see the ball move because the function to move it cannot perform unless the gamestate is set to "playing". As of now our gamestate is set to "paused".
We now need a way to get out of the pause state. So, let's make a new function that operates while we're in the "paused" state.
You can place this under your ballMovement() function you created earlier, not the call to it in the loop but the declaration above the main loop! Here's the code:

function paused()
pad = Controls.read()
screen:print(160,145,"Press X To Resume Play",white)
if pad:cross() then
gamestate = "playing"
end
end

In this function we set up pad to take in button input.
Under this we have made a message to print that asks the player to press X to resume play. Here we used the white color object we created earlier
Then we have an if statement that will set the gamestate to "playing" if the X button is pressed.
Earlier we set up a statement around our ballMovement() call that will only allow that function to perform if the state is set to "playing". So, this function we just created will allow us to set the state to "playing", which will allow the ballMovement() to perform.
But, first we haven't told the program to use the paused() function.
We know it should only be used if the state is set to "paused" so in our main loop, under drawImages() let's add the code below:

if gamestate == "paused" then
paused()
end

There. Now our game will have a function it can perform when it starts in the "paused" state, and it will perform that code until we hit the X button, which will then set the state to "playing", which will allow our ballMovement() function to perform.
See how useful states are!
Don't just sit there, save it and test it out!

Player 1 Button Input & Movement:
Next, we are going to add in the ability to move our player's paddle around. We will create a function called playerMovement(). Inside this function we are also going to add the ability to pause the game by pressing START.
Here is the function below. Add this in with your other function declarations. Above or below any of the others, just keep it in the same general area as your other function declarations.

function playerMovement()
pad = Controls.read()

if pad:up() and Player[1].y > 0 then
Player[1].y = Player[1].y - Player[1].speed
end

if pad:down() and Player[1].y < ( Resolution.height - Player[1].img:height() ) then
Player[1].y = Player[1].y + Player[1].speed
end

if pad:start() then
gamestate = "paused"
end
end

There's nothing really too complicated about this function. First, we have set up the pad to read in the controls.
Then, we check if the UP button in being pressed. If so, then our player's y position gets moved upward, since we are subtracting from the player's y.
We also check to see that the player's position is greater than zero, which is the top of the screen. This will keep our player from being above to go above the screen.
After that, we check for the DOWN button being pressed. This does the opposite of up and makes the player's y position move down the screen.
We also check that the player's y position is less than the screen's height minus the player (paddle) images's height, which is the bottom of the screen.
Just as we did the ball earlier with have to consider the player image's height, or else the player will go offscreen at the bottom until it's top right corner is at the bottom of the screen. This obviously would let the player go past the screen boundary.
Last we check for the START button. If pressed the gamestate will go into the "paused" state that we set up earlier. This will cause the game to perform only what's in the "paused" state just as it does when we first run the game.
Obviously, our function isn't of any use until we throw it somewhere in to our main loop. Let's do that now. What state of the game do you think our function call should be placed in?
Since we should only move our player while we're PLAYING then we should put it into the "playing" state.
So, place playerMovement() inside your "if gamesstate == "playing" code so that it looks something like the code below:

if gamestate == "playing" then
playerMovement()
ballMovement()
end

Notice how while making our Pong game we are focusing on making small parts of the game at a time, and not thinking of it as just a whole game.
A lot of this comes from the things we jotted down earlier!
Feel free to save and run the game. You can now move your paddle, without going past the boundaries of the screen.
Unfortunately, the ball goes right through the paddle...

Collision Detection:
Well, it won't be much of a Pong game until we make some collision code to make our ball bounce off the paddles.
The code we go over below will make more since if you've done the previous Collision tutorial.
We will create a function that will check for box collision, or the four corners of the images.
Place the function below along with your other function declarations, and then we'll go over it.

function checkCollision(obj1,obj2)
 if (obj1.x + obj1.img:width() > obj2.x) and (obj1.x < obj2.x + obj2.img:width() ) and (obj1.y + obj1.img:height() > obj2.y)
and (obj1.y < obj2.y + obj2.img:height() ) then

if (obj1.y > obj2.y) and obj1.y < (obj2.y + obj2.img:height()/2 ) then
obj1.yspeed = -3
else
obj1.yspeed = 3
end

if obj2 == Player[1] then
obj1.xspeed = 3
else
obj1.xspeed = -3
end

end
end

Here we created a function called checkCollision(). The function will take two arguments, obj1 and obj2. When we call this function later when will fill in the two arguments to make the function check if two objects (obj1 and obj2) have collided.
The first big long if statement is checking to see if two images are overlapping by getting the four corners of the images, and going from there to see if collision is happening.
For instance, if ball's x is greater than player 1's x, but ball's x is less than player 1's x plus player 1's width..then the ball has to be somewhere on top of the image.
Of course the y is also checked and has to be true for that as well.
The next "if" statement will perform only if we have determined that we are colliding, since it is nested within another "if" statement.
This code is checking whether it has collided with the top half or the bottom half of the paddle. It's saying that if, for instance, the ball's y is greater than the paddle's y but less than the paddle image's height divided by 2 (which is half the image) then let's make the ball's yspeed change to -3. This will make the ball go upward. Else, if it doesn't hit the top half, then it has hit the bottom half, in which we make the ball go downward. This will give a little variety to the play...rather than having the ball's y only change at the screen's edge.
We know that in Pong when the ball hits the paddle its horizontal direction reverses also. So, the last if statement does that.
Player 1 is on the left and Player 2 is on the right. So if the object we collided with is Player 1 then make the ball's x go right, if Player 2, go left.
Now, let's add some calls to the function inside our main loop. Once again we are adding to the "playing" gamestate, so change your main loop code to look like below:

if gamestate == "playing" then
playerMovement()
ballMovement()
checkCollision(Ball,Player[1])
checkCollision(Ball,Player[2])
end

Here we filled in the arguments we created for the function earlier. We call the function two times.
The first we are checking if the ball and Player 1 collide. The second if the ball and Player 2 collide.
When the function executes all the obj1 and obj2's will be replaced with the arguments we just entered in the calls.

Scoring:
As of now our ball continues traveling forever into the unknown once it exits the edges of the screen. So, what we should do next is make the ball stop and give either Player 1 or Player 2 a point on their score when the ball leaves the screen, and then reposition the ball back onscreen.
We should also display a message on the screen telling who scored a point, or display a winner if a score has gotten to 10 points.
Also, we should make the player press a button before the ball starts moving again, so he/she can be ready for it.
We are going to create a function called checkScore() that will be placed in our "playing" gamestate code.
Before we make the function, in your Variables and Tables section near the top of your code create this variable:

whoScored = nil

We will use this shortly. We assigned it a value of nil for now, which means nothing.

Here's the function. Place it with the other function declarations.

function checkScore()
if Ball.x < 0 - Ball.img:width() then
gamestate = "scored"
Player[2].score = Player[2].score + 1
whoScored = "Player 2"
Ball.x = 240
Ball.y = math.random(80,160)
Ball.xspeed = 3
end
if Ball.x > Resolution.width then
gamestate = "scored"
Player[1].score = Player[1].score + 1
whoScored = "Player 1"
Ball.x = 240
Ball.y = math.random(80,160)
Ball.xspeed = -3
end
end

Let's look at the first "if statement". This statement checks for the ball exiting to the left of the screen.
The left edge of the screen is coordinate zero, but the ball will have to be below zero by the width of it's image in order for it to be all the way off the screen. Zero minus the images width will give us a negative number. So when the ball makes it to that point past the screen's left edge we will start our scoring code.
First of all we put the gamestate to "scored", which is a new state for the game. In a bit we will make a function that performs while we are in this state.
We next add a point to Player 2's score since this is that player's scoring side.
Then we use the variable we created. We set it's value to "Player 2". We will use the variable to print who scored a point to the screen later on.
Next, we reset the ball's x position to 240, which will place the ball back on the screen.
Since this function sends the game out of the "playing" state and into the "scored" state, the ball will remain still until we leave the "scored" state.
Next, we set the ball's y (vertical) position to a random spot just as we did when we first started the game.
In our Pong we are going to send the ball towards the person who scored when it restarts, so we set it's xspeed to positive 3.
The second "if statement" does the exact same thing as the first, except this checks to see if the ball exits the right of the screen, and sets the score for Player 1.

Now, we need to call the function in our main loop to use it. Place it inside the "playing" gamestate so that your code resembles this:

if gamestate == "playing" then
playerMovement()
ballMovement()
checkCollision(Ball,Player[1])
checkCollision(Ball,Player[2])
checkScore()
end

If you save and run the game now and let the ball go off the screen, you'll see it reappear in the center of the screen, thanks to our code. Although you don't see it, the score gets added up when this happens.
Also, you'll notice that once the ball reappears that we can no longer make the game react to input.
This is because we sent the game in to the "scored" state, which we haven't programmed yet.
Before we get into that, let's create a small function that will print our Scores to the screen.
This is simple so we can get it over with. Place the function below in the usual area...

function drawScore()
screen:print(10, 5, "Player 1",white)
screen:print(10,15,Player[1].score,white)
screen:print(400, 5, "Player 2",white)
screen:print(400,15,Player[2].score,white)
end

Not much to explain here, it simply prints the scores to the screen at the top left and right sides of the screen. Now we have to call the function in our loop. Place the code:

drawScore()

...inside the main loop underneath the drawImages() call.
The reason we want it underneath is because we want the player and ball images to be draw first, and then the score afterwards. Why?
This way the the score will always be drawn on top of those images, and won't be covered up when the players or ball move over it.
So keep in mind sometimes when things don't work quite right, you may simply need to rearrange the order in which they perform.v You can save and test it now if you like.

Now, on to our next function.
Our next go is to get out of the "scored" state once we have entered it. We will do this with the hasScored() function. Place the function below with the others you have and we'll go over it:

function hasScored()
pad = Controls.read()
if Player[1].score == 10 then
screen:print(160,135, "Player 1 Wins The Game",white)
elseif Player[2].score == 10 then
screen:print(160,135, "Player 2 Wins The Game",white)
else
screen:print(160,135,whoScored .. " Scored 1 Point!",white)
end
screen:print(160,145,"Press X To Resume Play",white)
if pad:cross() then
if Player[1].score == 10 or Player[2].score == 10 then
Player[1].score = 0
Player[2].score = 0
end
gamestate = "playing"
end
end

We will be using this function when we are in the "scored" state.
The purpose will be to display what just happened to the players on the screen.
We use pad to set up button input in the function.
First, we check to see if Player 1 has scored 10 points, if so we display that Player 1 has won the game.
Using elseif we check the same for Player 2.
If neither of these are true then the only possible answer is that someone scored a point but hasn't won the game yet.
So, using else we print whoScored " Scored 1 Point!". Remember that variable we created earlier? It knows who scored from a previous function we made, and it will fill in which player scored, displaying for example, "Player 1 Scored 1 Point!".
Next we check for the X button to be pressed. Inside this check we will set the player's scores back to zero if we determine someone has scored 10 points. This will naturally restart the game.
We placed the code to reset the scores inside the button check, and then last we set the gamestate back to "playing".
This allowed us to be sure that the scores only get reset a single time, and not over and over, since this code will no longer perform once we leave the "scored" state.
We haven't set up a way to call the function yet.
Since we have to be in the "scored" state to use this function we'll need a new if statement in our main loop to check if we are in this state. We have a check for "playing" and "paused", now let's create one for "scored". Place the code below under or above the "if gamestate == "paused" then hasScored() end" statement in your main loop.
Place it OUTSIDE of that if statement,and not inside it, as it would only perform in the "paused" state!.

if gamestate == "scored" then
hasScored()
end

Now when our game enters the "scored" state it will have somewhere to go!.
Save it and give it a test run. We've almost got a full running Pong game now!.
The only issue we have left now is that our CPU opponent is sitting there like a bump on a pickle.
Time to fix that.

Simple Artificial Intelligence:
Now we will create some simple AI for Player 2.
The funny thing is, it's quite easy to make the paddle chase the ball and hit it.
The collision is already in place, so all we have to do is move the paddle towards the ball right?
Well yeah, but the problem there is that you will have a 100% completely impossible opponent to defeat.
If you only move the paddle towards the ball, and do nothing else...it will never miss a shot.
So we have to come up with a way to make the CPU player not only smart, but slightly dumb as well!
Before making the function let's add one final variable to our Variables and Tables section at the top of our code:

paddleSpot = math.random(Player[2].img:height() )

This variable will store a random height location from Player 2's paddle. We will use this shortly.

Let's go ahead and place the function in our function declaration area to and take a look:

function cpuAI()
if Ball.xspeed == 3 and Ball.x > 240 then
if Player[2].y + paddleSpot < Ball.y and Player[2].y < ( Resolution.height - Player[2].img:height() ) then
Player[2].y = Player[2].y + Player[2].speed
paddleSpot = math.random(Player[2].img:height() )
end
if Player[2].y + paddleSpot > Ball.y and Player[2].y > 0 then
Player[2].y = Player[2].y - Player[2].speed
paddleSpot = math.random(Player[2].img:height() )
end
end
end

Our function is called cpuAI() and will be the brains of that little paddle, we hope!
From the very first line I've given our CPU player a disadvantage. He will only move at all if the ball's xspeed is 3, meaning the ball is coming towards him, and also if the ball is past 240 horizontally on the screen, which is about half way.
This gives him a lot less time to get to where he's going.
The paddleSpot variable we created picks a random spot between the top and the bottom of the CPU paddle.
The CPU will try to hit the ball with that spot of the paddle, once we tell it to.
The second and third if statements accomplish this.
We add the player's y to the paddleSpot. This keeps up with that spot on the paddle even when it's moving.
We see if the spot is higher up on the screen than the ball's y position.
We also check that the CPUs y position is higher up on the screen than the resolution height minus the CPUs image.
That will give us the bottom of the screen.
If all that comes out as true then we will add Player 2's speed to his y position, which will move him downward.
This code will only move him down if he is positioned higher up than the ball and if he isn't at the bottom's edge of the screen.
Next, notice we reset the paddleSpot again. This will give him a new spot on his paddle to aim for so that he doesn't aim the exact same way every single time.
The last if statement does the same as the one before, except in reverse.
It will see if the ball is positioned higher than he is, and if he isn't at the top screen's edge.
If not, he will move up until his paddleSpot lines up with the ball's y position.
Study the code and you'll begin to understand it more.
We need to call the function in our main loop.
What state should our CPU move in? The "playing" state!
So, underneath ballMovement() add in this:

cpuAI()

Save and run it. You now have a challenging opponent, using very simple AI.
That pretty much covers our Pong game. It is now complete.

Challenge:
Using gamestate add a Start (or menu) screen to the game. You're on your own for this one.

Back To Tutorials

Please welcome jramada, our newest member.

Who's Online: 6 Guests, 0 Users

Total Members: 555
Total Posts: 13058
Total Topics: 1480
Total Categories: 8
Total Boards: 35

Recent Posts:

Re: Lua Loader? by Buddy4point0
Re: Lua Loader? by osgeld
Re: Lua Loader? by acer5050
Re: Lua Loader? by bumuckl
Re: Lua Loader? by acer5050
Re: Lua Loader? by bumuckl
Lua Loader? by acer5050
Re: PGELua Help - need term for a special rotation fix (mathematical issue) by bumuckl


 
Copyright © 2006-2007 www.EvilMana.com All rights reserved.
EvilMana Logo by emcp and Charlie