SL-积雪效果(hitTest)雪人(snowman)

 

 不错肯定用到碰撞检测(hitTest)有兴趣的去看看这篇文章吧http://www.andybeaulieu.com/Home/tabid/67/EntryID/160/Default.aspx

我就是用的这个方法。文中提到通过WriteableBitmap可以轻松的实现像素级的碰撞。

积雪效果(不是绘制的)通过雪花的碰撞挤压实现。同过一个WriteableBitmap来不断绘制雪花挤压后的效果,毕竟让SL不断生成元件想想都不合适。此次舞台雪花效果限制在200个,可以通过MAX_DOT_NUM来修改。

 

     当雪花与下边界的距离小于他的半径,就将其添加到WriteableBitmap中这就是第一次雪花的积留。(开始了)

 
代码
               if ((snow.Y + snow._size / 2>= this.LayoutRoot.Height)
                {
                    LayoutRoot.Children.Remove(snow);
                    _snowDots.Remove(snow);
                    addToWB(snow);
                    
continue;
                } 

 

 

碰撞检测肯定是在运动中执行的....

由于选件有点多...只使用一个DispatcherTimer很容易出现局部暂留的情况(卡...)。所以此次将运动和检测分为两个不同的DispatcherTimer,只是检测的频率要比运动频率高,道理是显而易见的。移动效果基本与上次没有差别,因此说一下碰撞检测

 

代码
                if ((snow.Y + snow._size / 2>= this.LayoutRoot.Height)
                {
                    LayoutRoot.Children.Remove(snow);
                    _snowDots.Remove(snow);
                    addToWB(snow);
                    
continue;
                } 

 

 

 

这个是通过WriteableBitmap来检测元件是否和先前积留的雪花有碰撞,只要一有碰撞哪怕是一个像素点那么....改元件将会被删除然后再wb中进行绘制。OK了这不是成功了么- -!上图...

              飘落时.. 

           

  堆积....

 

看出问题了吧,呵呵我们的雪花堆成花了而且堆积过程中本该透明的变黑了。 不知有没有人知道更好的处理办法,我用的进行或运算。
至于雪花堆积成花了这个肯定出来碰撞检测上。因为一开我们采用的是整个雪花全范围内的检测只要有一个像素点发生碰撞那么将会在wb中添加,我没的雪花运动不是直线的所以这种现象很容易发生。



OK
!下面来解决一下我们的碰撞函数。CheckCollision函数里的for循环改进....没错我们又增加了cpu的计算量。如果你在这里仍然用了1个线程那么卡是肯定的虽然cpu占有率并不是太高。

 
代码
             for (int i = 0; i < width; i++)
             {
                
for (int j = height/2; j < height; j++)
                {
                    
if (wb_snow.Pixels[i * width + j] != 0)
                     { 
//小元件像素点不空
                        offset = (offSetY + j) * wb.PixelWidth + offSetX + i;
                        
if (wb.Pixels[offset] != 0)
                         {
                            
if (offSetY < WBHEIGHT - DOT_SIZE_MAX )
                            {
                                
int index = (offSetY+height) * WBWIDTH + offSetX + width / 2;
                                
for (int t = index -3; t < index + 4; t++)
                                 {
                                    
for (int y = 0; y < 12; y++)
                                     {
                                        
int testp = y * WBWIDTH + t;
                                        
if (wb.Pixels[testp] == 0)
                                        {
                                            
return false;
                                        }
                                    }
                                }
                            }
                            
//info2.Text = "x:" + offSetX;
                            return true;
                        }
                    }
                }
                width
--;
            }

 

 

改进了雪花的检测范围,从全局检测编程下部巨型检测而且在超出雪花范围内检测其下部。就像模仿就一个物体如果大部分重力没有被承受那么它将继续下落。而且为了实现更逼真一点,雪花运动增添了直线运动。

 
         

代码
                Random r = new Random(seed);
                
if (d > 0.7)
                    snow.SelectRunFunction 
= true;
                
else
                    snow.SelectRunFunction 
= false;

 

d是一个随机值,我的想法是70%的概率的雪花是曲线运动30%是直线,不知是否准确。反正最终目的就是让有雪花石直线运动的,而且在生成之前添加随机值要比雪花生成后在随机一个值要好的多。看一下现在的效果
                                          


这样看来效果要好的多,由于或运算的原因有些部分会比较白。整个雪花堆积的思路大概就是这样...当然离真实逼真的积雪效果还是有很大差距。

/Files/sdmajun/snow.rar
下来开始我们的雪人...
这次我们+了一张采样图没错,是个雪人。用WriteableBitmap读取当做参数用。雪人图最后放,要不显得我的效果太差劲了
。这次我们将wb的绘制范围限制了在一个在以雪人为参数的范围内。很显然雪花堆积成就有个雪人的模样。
                 好吧,我承认我欺骗了你。
上图就明白了
                                   


看完图该明白个大概了。很显然我们的雪花由于重力原因没有支撑点所以我们胖乎乎的雪人凡是园出来的部分都没有了。你看上面那个是什么?什么是个模型。 那我真得谢谢你。上雪人图。
                                         


胖乎乎的肚子,圆圆的脸蛋都没了。我承认我的思路没了...再添加N个特殊点?我承认我败了谁能给个更好的思路么?

我用了一个很明显是个骗人的方法...一行行的把雪人给画出来。这个就不难了所以也不说多,雪人从下往上画。
我+了一个DispatcherTimer用来绘制雪人,如果某一行达到了要求范围即像素点为0的不能太多,或者达到了一定时间范围因为是随机的限定的界限不一定起作用从而可能导致绘制失败。看绘制过程

代码
public void DrawSnowman(object sender, EventArgs e)
{
if (_drawIndex <= 100)
{
_drawSnowman.Tick 
-= DrawSnowman;
_drawSnowman.Stop();
}

int count = 0;
int index = (_drawIndex - 1* WBWIDTH - 1;
for (int i = index + 250; i <= index + 420; i++)
{
if (wb.Pixels[i] == 0)
count
++;
}
if (count > 60)
{
_reCount
++;
if (_reCount < 20)
return;
}
for (int i = index + 200; i <= index + 431; i++)
{
wb.Pixels[i] 
= SnowmanWB.Pixels[i];
}
_drawIndex
--;
_reCount 
= 0;
}

 

 

学人啊你什么时候出来



效果大家看源码吧。增加了一个绘制按钮这个功能更加单不过可以看见雪花盖在雪人上。



综上,这个我粗略实现的方法(实在拙劣)。大家有什么更好的方法交流一下...另外
这里有个警告不知为何大家帮解决一下文件确实存在。我没解决那就别ctrl+f5了。还是直接看吧.../Files/sdmajun/snowman.rar

 

posted on 2010-01-04 10:06  MC_ma  阅读(558)  评论(0编辑  收藏  举报

导航