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

本文介绍了一种使用Silverlight通过碰撞检测实现积雪效果的方法,利用WriteableBitmap实现了像素级的碰撞检测,并通过不断绘制雪花挤压后的效果来模拟积雪过程。
 

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

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

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

 

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

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

 

 

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

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

 

ExpandedBlockStart.gif 代码
                 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占有率并不是太高。

 
ExpandedBlockStart.gif 代码
              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
-- ;
            }

 

 

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

 
         

ExpandedBlockStart.gif 代码
                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的不能太多,或者达到了一定时间范围因为是随机的限定的界限不一定起作用从而可能导致绘制失败。 看绘制过程

ExpandedBlockStart.gif 代码
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

 

转载于:https://www.cnblogs.com/sdmajun/archive/2010/01/04/1638700.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值