转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> VB.NET程序 >> 正文
Drawing & Animation II         ★★★★

Drawing & Animation II

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1906 更新时间:2009/4/23 16:39:28

Drawing & Animation

Using the Win32 GDI #2

This three part tutorial first appeared some years ago on the old VBExplorer.com . Since then several errors and bugs have been discovered by various users on the VBExplorer.com Forums. This version reflects the changes made to overcome the bugs and erros. The text will note where a bug correction and / or update has been done, and of course also why. 
A big ''''Thank you'''' goes out to all the people reading and reporting the bugs in the previous version of this tutorial. Please provide comments, questions, bug reports etc. at the VBExplorer.com forums in the Graphics & Game Programming section.


Backbuffering, AutoRedraw and Refresh

In the previous section we used the AutoRedraw property and the Refresh function to force a copy of the form to be stored in memory and then updated. The same thing can of course be accomplished on a picture box.

There is also an alternative to this scheme, namely BackBuffering. Backbuffering is a simple technique, where you keep a 慶opy?of the gaming field (display area) in a non-visible area. All the sprites and other drawings are drawn into the backbuffer, which is then drawn all at once onto the display area.

If we could view the process it would look something like this:

Step 1: Draw all the masks and sprites onto the non-visible back buffer

Step 2: Draw everything in the back buffer to the visible area

So why does this produce flickerless animation? The main reason is that we only use one Blit operation to draw everything we need from the backbuffer to the front display area. This disables all the intermediate updates, which might occur between each blit operation, and thus produces a clean drawing. Get it? Basically you are doing all the work with the sprites and masks off screen, where the game player doesn''''t see it and blitting to the play area once. The other way all the operations take place in the visible play area.

 

Which method is then the best method? Well, it depends on your type of application and the design you have made. The sample project BACKBUF found in BACKBUF.ZIP demonstrates both methods and times the amount of time elapsed. We tested both of the methods with this sample project and with some additional projects. All the empirical data from the tests conclusively demonstrate that neither method is faster. The best would of course then be the AutoRedraw ?Refresh method, since it does not use the extra picture box to store the backbuffer in. But it also depends on the size of the drawing area you have. If it is big, then the Refresh ?Autoredraw method -might appear slightly slower than the backbuffering scheme. So the choice is really up to you, test your game with both schemes and use the one you like best.

 

Sprite Animations and StretchBlt

Now we know how to move a sprite around the window, but usually that is not enough to form a complete game. Sometimes there is also a need to change the actual sprite image, in order to accommodate certain conditions of a game.

The actual implement of such a scenario is actually quite simple, it is just a matter of changing the actual sprite picture. So if we had a need of a small ball Note: Will change this to a small animated character instead rotating around the screen, we would simply make each rotation in a drawing program and draw each in a specified order. Very much like a little cartoon animation block.

In the sample project ANIMATION contained in ANIMATION.ZIP we will do just that, create a ball with shifting colors. The first thing to note is that so far we have used a picture box to hold each separate bitmap. If we were to do that for each sprite in a game with several animated sprites, we would be using up quite a number of picture boxes. So instead, we will draw all the animation frames of the sprite in just one bitmap, and only draw the part of this bitmap that we need. The bitmap would look like this:

Notice the apparent black sprite, which actually represents a black circle.

We already know that the sprite is 64 pixel wide and 64 pixels high (this was of course preset when the sprites were made). We also know that we need to feed the BitBlt function with information on only the upper left corner of the sprite, and the dimensions of the sprite. So it is just a simple matter of moving this upper left point from each frame to the other. Since the image only has one row of sprites, the Y position will be constant (always 0). So the only really challenging thing is to move the X position a given distance in pixels with each new frame we blit. To accomplish we must keep an eye out for the current frame, which is to be displayed. Using a simple variable as a frame counter does this. This frame counter is updated every time the frame is changed, so it will always have a value equal to the current frame. If we also use this variable as a multiplier to the constant width of the sprite, we actually get exactly what we want.

 

 

As you can see from the illustration, then the upper-left X position of a frame is equal to the FrameNumber ?1 multiplied by the width of the sprite. So by using this scheme we move the X position by an amount which is equal to the width of the sprite, on each update of the frame.

FrameNumber = (FrameNumber Mod MaxFrames) + 1

This actually ensures that the FrameNumber variable will never be more than MaxFrames and never less than 1. The method also produces a problem, since when we use it to get the X positions we will get values in the range from 64 (Frame 1) to 640 (Frame 10). These values represent the rightmost X position of the sprites, which is of no use to the BitBlt function. The solution is of course to simply subtract 1 from the FrameNumber when we calculate the X position, and thereby getting X values in the range of 0 to 576, or all the leftmost positions of the sprite frames.

The same thing could be employed to keep the sprite from moving out of bounds of the window:

X = (X Mod Me.ScaleWidth) + 1

Y = (Y Mod Me.ScaleHeight) + 1

So now that we have all this wonderful background information, it should be simple to implement in a timer event and draw the thing:


Private Sub TimerAnimation_Timer()

Static X As Long
Static Y As Long

''''Clear the form, since we do not have a background
Me.Cls

''''Draw the mask
BitBlt Me.hDC, X, Y, SpriteWidth, SpriteHeight, picMask.hDC, _
                    (FrameNumber - 1) * SpriteWidth, 0, vbSrcAnd

''''Draw the sprite
BitBlt Me.hDC, X, Y, SpriteWidth, SpriteHeight, picSprite.hDC, _ 
                    (FrameNumber - 1) * SpriteWidth, 0, vbSrcPaint

''''Update frame number
FrameNumber = (FrameNumber Mod MaxFrames) + 1

''''Update drawing positions
X = (X Mod Me.ScaleWidth) + 1
Y = (Y Mod Me.ScaleHeight) + 1 

''''Force an update of the form
Me.Refresh

End Sub

 

We employ the usual scheme of first drawing the mask and then the actual sprite. As you can see from the picture box with the masks, we have created a mask for all the sprites, and draw these mask frames in the same manner as the sprites. This would not be necessary in real life with this particular sprite example. Since each frame of this sprite''''s animation sequence is the same shape and therefore has the same transparent and visible areas we could have used the same mask for each circle.

Run the project and press the Start button. Observe how the sprite changes color as it moves down over the form.

More on Timing

This is all fine and good, but you may run into a situation where you do not want the same frame change (rate) as the timer interval. For example let''''s imagine that you have created a scene with some slow blinking lights which you want to blink once every second. If you were to blink the lights using the game loop, which we''''ll say is firing once every 20 milliseconds, the lights would blink so fast you wouldn''''t be able to see it. The problem here is to delay the blinking of the lamp, so it will only blink, or Blit, once each second and not every time the game loop is fired. That is why we will use the GetTickCount API, to check if a second has elapsed, and if it has, fire the

[1] [2] [3]  下一页


[Sql Server]Sql精妙语句--各种求值函数  [网页制作]网页表格之---多个表格纵向排列
[网页制作]JavaScript另类用法--读取和写入cookie  [网页制作]号称非常安全的上网工具---360安全浏览器介绍
[办公软件]信息技术教学篇---Word工具栏的显示、隐藏及四种菜…  [操作系统]开始菜单---运行命令大总结
[操作系统]网络转载---64位操作系统与32位的区别  [操作系统]ldap:///(没有响应)Windows无法访问指定设备、路径…
[网络技术]安全篇---交换机设置方法介绍  [聊天工具]Real10 & Xpdf installation on Linux Box
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台