Welcome to Hacking the PSP Sign in | Join | Faq

PSP Software Development

Started by Auri at 02-03-2006 11:01 PM. Topic has 0 replies.

Print Search
Sort Posts:    
   02-03-2006, 11:01 PM
Auri is not online. Last active: 9/2/2008 12:38:52 PM Auri



Top 10 Posts
Joined on 12-07-2005
Indianapolis, Indiana
Posts 3,679
Lua Development Lesson 2 by Yeldarb
Reply Quote

Lesson 02

The Basics

Lua Programming Techniques


Source: Yeldarb's Web Site

After having read Lua Lesson 01, you should have a basic concept of how to run Lua programs and how to setup a simple script. You are now ready to move on to some more advanced concepts that will prepare you to create fully featured applications and games.

In this tutorial, you will learn to: use if statements, display a background, load and display images, get button input, take screenshots, and make a loading screen, along with a bunch of other neato concepts.

So, basically this tutorial could be called "how to make a souped up, useless, graphical Lua script." But, alas, it's not. It's called "The Basics," because that's what this souped up, useless, graphical Lua script will attempt to teach you.

If you haven't read the first tutorial, I highly recommend it. If you decide to go on anyway, without reading it, and become baffled, and in the process having your mind transfored in to a gooey puddle of radioactive mush, don't come complaining to me. (Aside: actually it's not really that difficult, I just thought I'd add a little drama to the tutorial).

Before you start, you will need to download a zip file containing the images used in this tutorial. (The preceding phrase was a link, for those of you who skimmed right over it).

Now that we have all that introductory BS (baloney sandwich) out of the way, on to the tutorial!

For firmware 1.50 users, there's a nifty little trick that you can use (sorry 2.00+ people, it requires kernel mode which isn't yet available to you) to speed up your development cycle. By adding the following line into the top of your code, you can activate USB Disk Mode, which allows you to edit your script without having to exit out of it and go back through the menu. To enable this, create a new lua file and use this as the first line:
System.usbDiskModeActivate()
Now the USB port on the PSP will be activated when you run your script.

Next we are going to define our colors like we did in the first tutorial. We will be using pink, blue, orange, gray, and black. Logically, we will name our variables accordingly. So, to instantiate these color objects, we will enter the following lines of code:
pink = Color.new(255, 0 , 153)
blue = Color.new(0 , 153, 255)
orange = Color.new(255, 102, 0)
gray = Color.new(153, 153, 153)
black = Color.new(0 , 0 , 0)
If you have forgotten how these lines work, go back to the last lesson and refresh your memory.

Now we want to display a loading screen. Our loading screen will say "Loading: 0%" then "Loading: 1%" and so on and so forth until "Loading: 100%." To start it off, we need to print "Loading: 0%" to the screen. You should remember the screen:print function from Lua Lesson 01. But in case you don't, here's the code that you will need to insert:
screen:print(194, 136, "Loading: 0%", yellow)
screen.flip()
As you should recall, "screen:print()" will store our text in an offscreen buffer, and then "screen.flip()" draws that buffer to the screen.

Next, we need to load our images (which, if you missed it before, can be downloaded here). Extract the zip file into the folder where your script file is on your PSP. Then add this line. It will load the background.
background = Image.load("images/background.jpg")
Before we move on, let's get a firm understanding of what this line of code actually does. The first thing we see is a variable name, background. We then set that variable equal to the result of the function on the right ("Image.load()") using the assignment operator, or equal sign. The actual loading of the image comes through the "Image.load()" function which is built into Lua. It takes one parameter, the path to the image file we want to load. Our image is in the "images" folder, and the picture we want to load is "background.jpg." Remember, you must always use the file's extention when loading it (in this case, it was a jpeg file, so we used the extention ".jpg").

Now that we have loaded the background, we want to update our loading status text.
screen:clear()
screen:print(194, 136, "Loading: 20%", yellow)
screen.flip()
This should all be familiar to you by now. All, that is, except for the "screen:clear()." What do you suppose this does? No, it doesn't initiate the hyper flux capacitor. Nope, sorry, it doesn't make your PSP transparent. What's that? Yes, you in the back. Correct! It erases everything we have on the screen up to this point. It lets us start over with a clean slate.

Now we'll do the same process over again, but loading different images (and loading one sound):
circle = Image.load("images/buttons/circle_button.png")
down = Image.load("images/buttons/down_arrow.png")

screen:clear()
screen:print(194, 136, "Loading: 40%", yellow)
screen.flip()

l = Image.load("images/buttons/left_trigger.png")
left = Image.load("images/buttons/left_arrow.png")

screen:clear()
screen:print(194, 136, "Loading: 60%", yellow)
screen.flip()

r = Image.load("images/buttons/right_trigger.png")
right = Image.load("images/buttons/right_arrow.png")
boltsnd = Sound.load("music/comp.wav")

screen:clear()
screen:print(194, 136, "Loading: 80%", yellow)
screen.flip()

square = Image.load("images/buttons/square_button.png")
triangle = Image.load("images/buttons/triangle_button.png")

screen:clear()
screen:print(194, 136, "Loading: 90%", yellow)
screen.flip()

up = Image.load("images/buttons/up_arrow.png")
x = Image.load("images/buttons/cross_button.png")
splash = Image.load("images/lua.gif")

screen:clear()
screen:print(194, 136, "Loading: 100%", yellow)
screen.flip()
The one thing in this block of code that does need to be explained is the loading of the sound. The line 'boltsnd = Sound.load("music/comp.wav")' is what loads our sound file. Symantically, it is identical to the image loading code. The only real difference is that the "Sound.load()" method is defined in the "Sound" class rather than the "Image" class. You needent worry about this just yet, it may come up in some advanced programming later, or you may never have to deal with it (unless you learn Java, then you most definitely will).

After all of our stuff is loaded, we are just going to quickly pause at the "Loading 100%" so our user gets a chance to see it. To do this, we'll use the "waitVblankStart" function that we talked about at the end of Lesson 01.
screen.waitVblankStart(60)
This time we have passed a parameter to the function. This just tells it to pause for a certain amount of time. There are sixty Vblanks in a second, so this pauses our program at this point for exactly one second.

We've finished our loading screen (and our loading). Now it's time for the intro screen, thanks go to indianajonesilm, the author of PSP Air Hockey.

First things first, let's display the background.
screen:blit(0, 0, splash, false)
screen.waitVblankStart()
screen.flip()
This step is simple. To display the background, we use the "screen:blit" command. This is much like the "screen:print" command in that it writes to the offscreen buffer. But, in this case it is writing an image rather than text. The first two numbers (as in "screen:print") are the x and y coordinates. Since our image is the since our image is the size of the screen, we left these two numbers as zero (so that the picture would start in the top-left corner). "splash" is the variable name that we used for the image. And then we will pass "false" for the alpha parameter. Our image doesn't have transparency, so we dont need this flag set.

Now we have the background displayed on our intro screen! But, of course, the intro screen is not done. We need... MUSIC! Or... at least some sound. To accomplish this, we simply need to add one line:
boltsnd:play()
This is where Lua really shines. It may not provide a whole lot of flexibility for advanced coders, but it is lines like this that make it such a great programming language. In C, you would have had to install all sorts of libraries, linked them, and not to mention programmed in a bunch of routines to handle the sound. With Lua, this is all done for you, and you can start playing sound with just a single line of code.

The line is fairly straightforward, we just call the "play()" function for our "boltsnd" variable (which we already loaded our sound clip into above). That's really all there is to it!

Now we are going to flip the screen again, set the volume, and wait on the screen until the sound is finished. Put this in your code:
screen.waitVblankStart(240)
screen.flip()
Music.volume(128)
As we touched on before, there are sixty Vblanks in a second, so we are pausing the program for four seconds (240/60 = 4). "screen.flip()" just updates the screen. And, Music.volume(128) sets the volume to 128; this is the highest that the volume goes (0 is the lowest). Now our loading screen (and our intro) are done! Hooray! Give your self a big hug. (Aside: whitehawk is a little weird for adding that in, but hey who am I, the editor, to judge?)

But it's not all fun and games yet, we still need to code the actual program. So, let's go.

The first thing we're going to do is start our game loop and display the background.
while true do
          screen:blit(0, 0, background, false)
Remember from the first tutorial when we used the infinite loop at the end? Well, this uses the same concept, except we are going to do the main bulk of our program until the user exits the script rather than just pausing. The other line (obviously, since this is about the gagillionth time we've done this) writes the image into the offscreen buffer.

We are almost to the part of our code where we will interpret button input, but first we need to get the state of the buttons. We do that through the "Controls.read()" function, like this:
          pad = Controls.read()
This saves the button states to a variable, "pad." It is like taking a snapshot, if we never redid this line, it would always contain the button status that we have at this specific moment in time. But, remember, this is still in the game loop, so every time our loop goes through it will update the variable.

Ready for interpretting the input? Yeah, I'll bet you are, but hold your pants on. We need to print the instructions on the screen first (how else are our users going to know what to do?).
          screen:print(135, 251, "Press 'Start' to restart", blue)
          screen:print(110, 261, "Press 'Select' for a screenshot", blue)
          screen:print(383, 35, "Support:", black)
          screen:print(365, 45, "PS3Lounge.net", orange)
          screen:print(365, 55, "scriptscribbler.com/psp", gray)
          screen.flip()
Now we have our instructions on the screen (along with a little bit of self promotion).

NOW it is time for the interpretation of the button input. Did you keep your pants on? Oh God, I didn't want to hear that. It was a rhetorical question, RHETORICAL!

What is going to happen in our little application is this:

When we press [X], it will display a picture of the PSP's X button on the screen.
When we press [^], it will display a picture of the PSP's UP button on the screen.
When we press [L], it will display a picture of the PSP's Left Trigger on the screen.
And so on and so forth.

Now that it's understood what we are attempting to do, let's take a gander at trying to understand how we will write the code. We are going to use a series of "if" statements. "If" statements are perhaps the most widely used programming convention. What they allow your program to do is make decisions. "If this, do that. If not this, then do something else." Now that you understand what "if" statements do, let's look at how we make them do it. Here's the code we are going to use for the first button:
          if pad:cross() then                     screen:blit(50, 228, x)                     screen.flip()           end
First of all, "pad:cross()" is the way that we check to see if when the "pad" variable was set, the [X] button was pressed. It will return "true" if it was, and "false" if it wasn't. If it is returned true, the code between "then" and "end" is run. It it is returned false, the code in between those two identifiers is skipped. The code, of course, is our code to display the image of the [X] button.

The code for the first button is set, now we just need to do the same thing for each of the other buttons. Here's the code:
          if pad:circle() then
                    screen:blit(90, 195, circle)
                    screen.flip()
          end

          if pad:triangle() then
                    screen:blit(45, 165, triangle)
                    screen.flip()
          end

          if pad:square() then
                    screen:blit(15, 195, square)
                    screen.flip()
          end

          if pad:up() then
                    screen:blit(60, 40, up)
                    screen.flip()
          end

          if pad:right() then
                    screen:blit(90, 65, right)
                    screen.flip()
          end

          if pad:down() then
                    screen:blit(60, 80, down)
                    screen.flip()
          end

          if pad:left() then
                    screen:blit(30, 65, left)
                    screen.flip()
          end

          if pad:l() then
                    screen:blit(4, 6, l)
                    screen.flip()
          end

          if pad:r() then
                    screen:blit(403, 4, r)
                    screen.flip()
          end
Congratulations! You have finished your first true Lua Application. So we're done... or are we? (*cue dramatic music*)

Nope. We're not. But don't fret, the bulk of the work is done, we only have five lines to go. We need to put in the code to restart the application when you press [START] and to take a screenshot when you press [SELECT].

We'll do the screenshot code first:
          if pad:select() then screen:save("screenshot.tga") end
Notice that we did this whole "if" statement on one line. It's perfectly legal. The function "screen:save()" just takes a screenshot to the file that we specify inside the parenthesis. In this case, we are saving our screenshot to "screenshot.tga."

Now we'll just make the code to restart when the user presses [START]:
          if pad:start() then
                    break
          end
The break statement will exit us out of the infinite while loop (the game loop), effectively restarting the script.

And finally, we must insert a line to terminate our while loop (so the Player knows it's time to go back to the beginning of the loop and start over).
end
Now we are done! Remember that hug you gave yourself before? Well, don't even think about doing it again, because it creeped me out. But you can go test your script on your PSP! Congratulations. You are now a developer.

Special thanks to: Shine, indianajonesilm, and PSPUpdates.

Be sure to add the feed to your RSS Aggregator (or Google Homepage, or Firefox Live Bookmark) to stay updated with the latest tutorials.

If you have enjoyed this tutorial and have a spare buck or two, please consider donating to the author.

If there's a calling, I will consider making more tutorials. Please contact me with your feedback on the tutorials and on what you'd like to see in the next lessons. My e-mail is whitehawk45 [at] gmail [dot] com.


---
Author, Hacking the PSP
www.hackingpsp.com

   Report 
Hacking the PSP » Hombrew Softwar... » PSP Software De... » Lua Development Lesson 2 by Yeldarb

Powered by Community Server, by Telligent Systems