- Return to Touhou Danmakufu
Download them at: www.stephenware.com/th_dnh/bg_ex.zip
Section 0: Before You Try This
This tutorial assumes you have a basic familiarity with danmakufu scripting in general. If you don't understand that yet, this tutorial won't really help you. Sorry. I recommend looking at the Touhou Danmakufu section. There's also a danmakufu-specific wiki.
Section 1: The Basics
Okay, first off, download the sample code: www.stephenware.com/th_dnh/bg_ex.zip
Extract it somewhere inside of your danmakufu scripts directory.
For this section, we will be looking at the script file bg1.txt
First off - if you've worked with danmakufu code before, you've probably seen some of the drawing functions. In fact, if you've made a spellcard script which has an enemy character, you've already used some of what I'm going to show here. This section introduces the simple commands to draw 2D graphics in danmakufu.
LoadGraphic ( <the_image> ) - This function will load an image file into memory, and get it ready for danmakufu to use. This should only be called once for each image you want to load. <the_image> can either be a string indicating the path of the file, or a string variable holding that path. Important note: if danmakufu can't find the file you give it, there will not be any warning or error, and any graphic you try to draw with that image will just not appear.
SetTexture ( <the_image> ) - This will set the given image file as the currently active one. This means that it will be the one that will be drawn when you instruct danmakufu to draw, until you change it with another call to SetTexture.
SetGraphicRect ( <left-side x> , <top-side y> , <right-side x> , <bottom-side y> ) - This will set the region of the selected image file to draw. To draw all of an image file that is M pixels wide by N pixels tall, use SetGraphicRect(0, 0, M, N). The coordinates of the region selected is known as "texture coordinates."
IMPORTANT NOTE on texture coordinates:
- The left and top side coordinates are the pixel you want to start with, with (0, 0) being the upper-left corner. The right and bottom side coordinates are one past the coordinates of the last pixel in the image you want to use.
- Think of it this way. The left and top coordinates give a >= (greater than or equal) limitation, while the right and bottom coordinates give a < (less than) limitation.
DrawGraphic ( <x> , <y> ) - This draws the currently selected image to the screen at the given coordinates. These coordinates are the same as the coordinates used for positioning the player, enemy, and bullets. Important note: the coordinates you pass this function give where the CENTER of the image will be drawn.
DrawText ( <text> , <x> , <y>, <size>, <alpha> ) - This will draw text on the screen. <text> can be just about any basic value, including both strings and numbers. The coordinates passed here indicate the top-left of where the text is output. <size> determines how big the font will be, by giving the height of the text. <alpha> is used for alpha-blending, which will be discussed later in Section 2.
DeleteGraphic ( <the_image> ) - This will remove an image file from danmakufu's memory. This is usually called in your script's @Finalize, to clear up the memory that was used by the graphic.
Using These Commands
To draw a graphic, the following must be done:
1) In your script's @Initialize, you must load the image file using LoadGraphic(). 2) In your script's @DrawLoop or @BackGround, you must do the following: 2a) Set the current image to the image file you want using SetTexture() 2b) Set the texture coordinates (the area of the image file to use) with SetGraphicsRect() 2c) Draw the graphic, using DrawGraphic()
To draw text, simply call the DrawText() function in either @DrawLoop or @BackGround
Important: anything that you draw is cleared the next frame, so things must be drawn every frame for them to continuously appear on the screen. This isn't much of an issue, though, since @BackGround and @DrawLoop are both run every frame anyway.
- Whenever using an image file, setting a pixel to pure black (RGB 0 0 0) will result in that pixel being transparent when drawn in danmakufu. If you want a black color, use a close RGB value (for example, RGB 1 1 1).
- I might be missing something, but as far as I can tell @BackGround only works in stage scripts, not in enemy scripts. This sort-of makes sense, anyways.
- As you might notice in the script file, I used a variable named iamgefile to store the path to the image I was using. This is a good idea, and makes it easier to reference graphic files generally.
- DrawText() can be useful for quite a few things. When I'm having some trouble getting a script to work correctly, I sometimes use DrawText() to output some key variables to make sure they're taking on the right values. You can also use this function to make a simple menu in your script.
Section 2: Simple Effects
Here, I'll show you how to do a few simple effects to add to the rendering we did in Section 1. For this section, we will be looking at the script file bg2.txt
To tile a graphic means to display multiple copies of it next to each other, basically. Tiling a graphic is actually really simple in danmakufu.
When passing arguments to the SetGraphicRect() command, if you set an argument outside of the range of the image file's coordinates, danmakufu will automatically wrap around the image and tile it for you!
For example, if we have an M by N image, and we want to tile it twice horizontally, we could say: SetGraphicRect(0, 0, 2*M, N); and danmakufu would automatically tile two copies of the texture horizontally.
Rotation in 2D
To rotate a graphic, we use this command:
SetGraphicAngle ( <rotation about x> , <rotation about y> , <rotation about z> );
However, since we're working in 2D graphics, we will always set <rotation about x> and <rotation about y> to zero. Set <rotation about z> to the angle you want to rotate the graphic, in degrees.
Just like the other "Set" functions, this needs to be called before you call DrawGraphic().
Scaling, or changing the size of a graphic, is pretty simple. Just use:
SetGraphicScale ( <x-scale> , <y-scale> );
This will make the drawn graphic <x-scale> times as wide, and <y-scale> times as tall.
Just like the others, SetGraphicScale() comes before you call DrawGraphic().
Alpha blending is a technique which gives objects a transparent appearance. To use alpha blending, use the following command:
SetAlpha ( <alpha value> );
<alpha value> is a value between zero and 255, and indicates how opaque the drawn object is. At 255, it is fully solid, which at zero, it is completely see-through. Giving values in-between yields a partially see-through graphic being drawn.
Again, SetAlpha() must come before the DrawGraphic() you want it to have an affect.
The Importance of Drawing Order
When drawing things like we are doing currently, the order in which things are drawn is very important.
To make it simple, think of each object we draw as a separate layer we put on top of the previous things that have been drawn. If the new object overlaps an older one, the new one will be seen over the older one.
Danmakufu's drawing algorithms work the same way here. Every item you draw will obscure anything else that is under it (more or less depending on the current alpha value, of course).
The Updated Draw Function Order
With what we know now, here's the full way to draw a graphic:
1) In your script's @Initialize, you must load the image file using LoadGraphic() 2) In your script's @DrawLoop or @BackGround, you must do the following: 2a) Set the current image to the image file you want using SetTexture() 2b) Set the texture coordinates (the area of the image file to use) with SetGraphicsRect() 2c) Set the alpha value with SetAlpha() 2d) Set the rotation with SetGraphicAngle() 2e) Set the scaling with SetGraphicScale() 2f) Draw the graphic, using DrawGraphic()
- Of course, you do not need to set every different value for every different thing you draw. For example, in the sample code I only call SetTexture() once and then use it to draw two instances of that graphic on screen.
- In a similar vein, ALWAYS set, at the beginning of @DrawLoop or @BackGround, any value you change later. You'll notice that I call SetAlpha(255); at the start of @BackGround. Normally, this would be unnecessary, since that is the default value. But, since I later call SetAlpha(160);, I need to clear that value (which is left over from the last run-through of @Background), or it will apply to the first image as well.
Section 3: Section 3: Intro to 3D
Here, we start to look at danmakufu's 3D capabilities. For this section, we will be looking at the script file bg3.txt
3D Coordinates in Danmakufu
When learning to draw in 3D, the first thing to learn is, of course, the coordinate system.
Danmakufu's coordinate system can be pretty simply described:
- the Y axis is vertical, with positive pointing upward
- the X and Z axes make the horizontal plane.
The Camera Analogy
When working with 3D graphics, it helps to think of the view as a camera, looking at a certain point in space. To set up the camera for 3D drawing in danmakufu, use these functions:
SetViewTo ( <x> , <y> , <z> ) - Sets the point in space which the camera is looking at. This, as you can see, is given in simple three-space coordinates.