Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 60 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
60
Dung lượng
0,96 MB
Nội dung
Following is the source code. Texture* renderTarget1=NULL; Texture* renderTarget2=NULL; Font* font=NULL; VectorShape* shape=NULL; Timer timer; bool flip=false; int seconds=0; int counter1=0,counter2=0; int rate1=0,rate2=0; bool game_init(HWND window) { font = new Font("System",12); renderTarget1 = new Texture(); renderTarget1->createRenderTarget(400,400); renderTarget2 = new Texture(); renderTarget2->createRenderTarget(400,400); shape = new VectorShape(); return true; } void game_update(float deltaTime) { if (flip) { g_engine->savePrimaryRenderTarget(); renderTarget1->renderStart(false, true); for (int n=0; n<100; n++) { Vector2 start( rand()%400, rand()%400 ); Vector2 end( rand()%400, rand()%400 ); float size = (float)(rand()%10); Color color(rand()%255,rand()%255,rand()%255,rand()%255); shape->drawD3DXLine(start,end,size,color); counter1++; } renderTarget1->renderStop(); g_engine->restorePrimaryRenderTarget(); } else { g_engine->savePrimaryRenderTarget(); renderTarget2->renderStart(false, true); for (int n=0; n<100; n++) { 460 Chapter 15 n Rendering to a Texture Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Color color(rand()%255,rand()%255,rand()%255,rand()%255); Vector2 start( rand()%400, rand()%400 ); Vector2 end( rand()%400, rand()%400 ); int size = rand()%10; shape->drawLine(start, end, size, color); counter2++; } renderTarget2->renderStop(); g_engine->restorePrimaryRenderTarget(); } } void game_render2d() { static ostringstream ostr; ostr.str(""); ostr << "D3DXLine: " << rate1 << " lines/sec"; font->Print(0,0,ostr.str()); //draw render target 1 { Sprite* target = new Sprite(); target->setPosition(0,20); target->setImage( renderTarget1 ); target->RenderFast(); delete target; } ostr.str(""); ostr << "VectorShape: " << rate2 << " lines/sec"; font->Print(450,0,ostr.str()); //draw render target 2 { Sprite* target = new Sprite(); target->setPosition(450,20); target->setImage( renderTarget2 ); target->RenderFast(); delete target; } font->Print(900,0, Octane::ToString(seconds) + " SECS"); if (timer.Stopwatch(1000)) { flip = !flip; Drawing Vector Shapes 461 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com rate1=counter1; counter1=0; rate2=counter2; counter2=0; seconds++; } } void game_event(Octane::IEvent* e) { switch (e->getID()) { case EVENT_KEYRELEASE: KeyReleaseEvent* evt = (KeyReleaseEvent*) e; switch (evt->keycode) { case DIK_ESCAPE: g_engine->Shutdown(); break; } break; } } Scrolling Background Layers There are quite a few game genres that are based on scrolling backgrounds. There are the vertical scrollers, usually shoot-em-up games, and the sideways scrollers. Of the latter, there are two main categories of games—side-scrolling platformer games, and side-scrolling shoot-em-ups. But there’s also a third type of game that can be made when a background scroller is available—a top-down view game such as the traditional RPG (role-playing game) popularized by games such as Zelda and Ultima. Bitmap Layers We’ll start by learning how to create a scroll buffer in memory using our Texture class, and then render something onto that memory texture—and presto, we’ll have a scrolling layer. Beyond that, the ability to render the layer at any location, to any target rectangle size, and with any alpha level, provides for some very advanced gameplay capabilities for the aforementioned genres. Our Layer class will function at a high level, taking care of most of the lower-level details like creating the scroll buffer, filling in the scroll buffer with a bitmap, and making it 462 Chapter 15 n Rendering to a Texture Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com possible to render anything onto the scroll buffer (such as tiles from a tile sheet). We’ll see how to use the Layer class shortly. Layer Class Header Here is the interface definition for the Layer class. Of particular note is the createBounded() and createWrapping() functions. These two functions will create a scrollable layer buffer (as a Texture) that is suited for rendering a scrolling level with distinct boundaries, as well as being suited for rendering a seamless texture repeatedly so that the appearance of endless scrolling is achieved. An endless scrolling layer is helpful in a game when you want the background to appear to go on for a long time without actually consuming huge amounts of memory in the process—so we fake it with a repeating or seamless texture and just wrap it around the edges. For this to work, we have to create a scroll buffer that is four times larger than the source image, and then paste the source image into the four corners of the buffer. This makes it possible to wrap the texture endlessly, as long as the scroll buffer is twice the resolution of the viewport (which might be the entire screen or just a small window). class Layer { private: int bufferw,bufferh; int windoww,windowh; public: Texture *texture; double scrollx,scrolly; Layer(); virtual ~Layer(); int createBounded(int bufferw, int bufferh, int windoww, int windowh); int createWrapping(Texture *seamlessTex); //these are just passed on to Texture bool renderStart(bool clear = true, Color color = Color(0,0,0,0)); bool renderStop(); //updating the scroller void updateBounded(double scrollx,double scrolly); void updateBounded(Vector3 scroll); void updateWrapping(double scrollx,double scrolly); void updateWrapping(Vector3 scroll); //drawing Scrolling Background Layers 463 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com void drawBounded(int x,int y, Color color = Color(255,255,255,255)); void drawWrapping(int x,int y, Color color = Color(255,255,255,255)); }; Layer Class Implementation The Layer class does a lot of work for us, making it actually quite easy to build a scrolling game out of it. Note the two update functions, updateBounded() and updateWrapping()—these functions must be called from the game’s update() function, as they will refresh the scroll buffer based on the current scroll position. Note secondly the two rendering functions— drawBounded() and draw- Wrapping() . You can’t draw a bounded scroll buffer with the drawWrapping() function, and vice versa, because they are not interchangeable. It might be interesting to abstract the two forms of scrolling with a property and have the Layer class decide how to update and render its buffer based on the programmer’s preference. But the class does a good job as is, and that might be suitable for a subclass suited for a specific game genre. Layer::Layer() { bufferw = bufferh = 0; windoww = windowh = 0; texture = NULL; scrollx = scrolly = 0.0; } Layer::~Layer() { if (texture) { delete texture; texture = NULL; } } /** Creates a layer; dimensions must be within 256 to 4096 for the primary window output used for all rendering **/ int Layer::createBounded(int bufferw, int bufferh, int windoww, int windowh) { this->bufferw = bufferw; this->bufferh = bufferh; this->windoww = windoww; this->windowh = windowh; //these are arbitrary, just chosen to prevent huge memory if (bufferw < 256) return 1; 464 Chapter 15 n Rendering to a Texture Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com else if (bufferw > 4096) return 2; if (bufferh < 256) return 3; else if (bufferh > 4096) return 4; texture = new Texture(); texture->createRenderTarget(bufferw,bufferh); return 0; } // A seamless image can be wrapped top/bottom or left/right int Layer::createWrapping(Texture *seamlessTex) { windoww = seamlessTex->getWidth(); windowh = seamlessTex->getHeight(); bufferw = windoww*2; bufferh = windowh*2; texture = new Texture(); texture->createRenderTarget(bufferw,bufferh); texture->renderStart(true, true, Color(0,0,0,0)); RECT source = seamlessTex->getBounds(); D3DXVECTOR3 center(0.0f, 0.0f, 0.0f); //upper left quadrant of scroll buffer D3DXVECTOR3 position(0.0f, 0.0f, 0.0f); g_engine->getSpriteObj()->Draw(seamlessTex->texture, &source, ¢er, &position, 0xffffffff); //upper right quadrant of scroll buffer position.x = (float) source.right; g_engine->getSpriteObj()->Draw(seamlessTex->texture, &source, ¢er, &position, 0xffffffff); //lower left quadrant of scroll buffer position.x = 0; position.y = (float)source.bottom; g_engine->getSpriteObj()->Draw(seamlessTex->texture, &source, ¢er, &position, 0xffffffff); //lower right quadrant of scroll buffer position.x = (float)source.right; g_engine->getSpriteObj()->Draw(seamlessTex->texture, &source, ¢er, &position, 0xffffffff); texture->renderStop(true); return 0; } // Pass thru to Texture: begin rendering to texture Scrolling Background Layers 465 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com bool Layer::renderStart(bool clear, Color color) { return (texture->renderStart(clear, true, color)); } // Pass thru to Texture: done rendering to texture bool Layer::renderStop() { return (texture->renderStop(true)); } void Layer::updateBounded(double vx,double vy) { scrollx += vx; scrolly += vy; if (scrollx < 0) scrollx = 0; if (scrollx > bufferw - windoww - 1) scrollx = bufferw - windoww - 1; if (scrolly < 0) scrolly = 0; if (scrolly > bufferh - windowh - 1) scrolly = bufferh - windowh - 1; } void Layer::updateBounded(Vector3 vel) { updateBounded(vel.x,vel.y); } void Layer::updateWrapping(double vx,double vy) { scrollx += vx; scrolly += vy; if (scrolly < 0) scrolly = bufferh - windowh - 1; if (scrolly > bufferh - windowh - 1) scrolly = 0; if (scrollx < 0) scrollx = bufferw - windoww - 1; if (scrollx > bufferw - windoww - 1) scrollx = 0; } void Layer::updateWrapping(Vector3 vel) { updateWrapping(vel.x,vel.y); } void Layer::drawBounded(int x,int y, Color color) { RECT srect = { (long)scrollx, (long)scrolly, (long)scrollx+windoww, (long)scrolly+windowh }; D3DXVECTOR3 pos( (float)x, (float)y, 0.0f ); g_engine->getSpriteObj()->Draw( texture->texture, &srect, NULL, &pos, color.ToD3DCOLOR() ); 466 Chapter 15 n Rendering to a Texture Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com } void Layer::drawWrapping(int x,int y, Color color) { RECT srect = { (long)scrollx, (long)scrolly, (long)scrollx+windoww, (long)scrolly+windowh }; D3DXVECTOR3 pos( (float)x, (float)y, 0.0f); g_engine->getSpriteObj()->Draw( texture->texture, srect, NULL, &pos, color.ToD3DCOLOR() ); } Scrolling Layer Demo To demonstrate the Layer class, I present you with a program called the Scrolling Layer Demo. This demo creates four layers, each with random shapes rendered onto them so you can clearly discern each one. Figure 15.2 shows the deepest layer that is behind the other three. This layer scrolls at the slowest speed to simulate parallax distance. These layer images are quite large—1800 Â 1800— because that is the size of the scroll buffer. Figure 15.2 The fourth background layer does not scroll so it is only the size of the viewport (900 Â 600). Scrolling Background Layers 467 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The next figure shown in Figure 15.3 shows the third layer, drawn over the top of the fourth layer, and containing similar box shapes in a different color. This layer will also scroll more slowly than the two in front of it, but slightly faster than the fourth one behind it. The second layer is shown in Figure 15.4. This layer moves slightly faster than the previous one, and is filled with random boxes. Finally, the first and final layer, shown in Figure 15.5, is drawn over all of the others with alpha transparency making it possible to see each successive layer below, all the way to the fourth layer at the bottom (or back, depending on how you visualize it). Figure 15.3 The third background layer is the size of the bounded scroll buffer (1800 Â 1800) and filled with random yellow boxes. 468 Chapter 15 n Rendering to a Texture Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The Scrolling Layer Demo is shown with all four layers moving together at different speeds to produce a parallax effect. See Figure 15.6. In the code listing for this program, note that redundant code (including most of the comment and error handling lines) has been omitted for space. Please see the complete project for these details. Font* font = NULL; Font* font2 = NULL; Layer *layer1 = NULL; Layer *layer2 = NULL; Layer *layer3 = NULL; Layer *layer4 = NULL; VectorShape *shape = NULL; Figure 15.4 The second background layer is the size of the bounded scroll buffer (1800 Â 1800) and filled with random green boxes. Scrolling Background Layers 469 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... power? An engine performs work Every component is crucial to the correct running of the engine, but the engine is far more than just the sum of its parts Let’s follow the same analogy when thinking about our game engine, and then work on putting the components together, from individual pieces to a whole machine that can produce work An entity manager is one such means to producing work within the engine. .. Version - http://www.simpopdf.com Entity Management Engine: :Update Located in the Engine. cpp file, the Engine: :Update() function is the engine core, called directly from the WinMain while loop, and residing at the lowest level of the engine Here is the complete source code for the function with the new entity manager code highlighted in bold: void Engine: :Update( float deltaTime ) { static float accumTime=0;... layer1->renderStart(false); font->Print(0,0,"LAYER 1"); layer1->renderStop(); } bool game_ init(HWND window) { font = new Font("Arial Bold",18); shape = new VectorShape(); g _engine- >savePrimaryRenderTarget(); createlayer1(); createlayer2(); createlayer3(); createlayer4(); g _engine- >restorePrimaryRenderTarget(); g _engine- >setSpriteIdentity(); return true; } void game_ update(float deltaTime) { float vx = deltaTime*velx*20.0;... sprites n Managed meshes Building an Entity Manager The entity management system in a game engine shouldn’t care what type of object you add to it, as long as that object is derived from a base entity You should be able to subclass an entity into as many different entity types as you want to use in your game! For our game engine, we’ll support the Sprite, Mesh, and BoneMesh classes (created in previous... manager that you want to control with script code down the road Up to this point, we have been adding new features to the game engine via new Cþþ classes for such things as meshes, sprites, terrain, and so forth Those classes do not make a game engine; they are merely tools A true engine must do something other than just offer up classes! Imagine it this way: You have a block, crankshaft, heads, camshafts,... font2->Print(300,300,"LAYER 1"); layer1->renderStop(); } bool game_ init(HWND window) { font = new Font("Arial Bold",18); font2 = new Font("Arial Bold",24); shape = new VectorShape(); g _engine- >savePrimaryRenderTarget(); createlayer4(); createlayer3(); createlayer2(); createlayer1(); g _engine- >restorePrimaryRenderTarget(); g _engine- >setSpriteIdentity(); return true; } void game_ update(float deltaTime) { switch (direction)... Rather than just consuming the classes provided by the engine, we will have the engine itself actually perform some gameplay processing internally Up to this point, we have been manually cranking our engine, but now it’s time to start it up! An entity class should provide base properties and functions that will be shared by all entities (regardless of gameplay functionality) We want to be able to add an... that makes it possible to add, find, and delete entities from the game code In the engine itself, we need to automatically move, animate, and draw entities based on their properties This is the part where game programming really starts to get fun, because at this point we’re working at a higher level, more in the realm of designing gameplay than doing low-level stuff like rendering This automated functionality... Unregistered Version - http://www.simpopdf.com Building an Entity Manager 491 Modifying the Engine The engine will need to be modified to support entity management This is the part where we begin to take the components (Entity, Sprite, Mesh, and so on) and assemble them into a functional engine We’ll begin with some changes to the Engine class When a managed entity is being updated or rendered, there are... collisions, etc.—we may want to apply behaviors to the object to influence it according to the requirements of the gameplay These two events are fired off through the engine s event system and received by the gameplay code’s game_ event() function Event Changes We have need for two new events in the engine to accommodate entity update and render notifications enum eventtype { EVENT_TIMER = 10, EVENT_KEYPRESS . game genres that are based on scrolling backgrounds. There are the vertical scrollers, usually shoot-em-up games, and the sideways scrollers. Of the latter, there are two main categories of games—side-scrolling platformer. games—side-scrolling platformer games, and side-scrolling shoot-em-ups. But there’s also a third type of game that can be made when a background scroller is available—a top-down view game such as the traditional. VectorShape(); g _engine- >savePrimaryRenderTarget(); createlayer4(); createlayer3(); createlayer2(); createlayer1(); g _engine- >restorePrimaryRenderTarget(); g _engine- >setSpriteIdentity(); return true; } void game_ update(float deltaTime) { switch (direction)