쇼티예요.
종전의 팁 오브 더 데이에서는,
여기서 정보를 충분히 찾을 수 있는 것이 나왔기 때문에(WCF를 실버라이트에서 쓰는 법).. 생략을 했구요.
이번 TTD에는 바로, 이것입니다!
네. 바로 '눈이 오는 효과 내기'가 되겠습니다. 조금.. 포스팅이 길더라구요.
여기에, 이분이 구현하신 데모 사이트가 있습니다.
(http://silverlight.services.live.com/invoke/66033/Snowfall/iframe.html)
또, 실행을 시켜보시면 아시겠지만 설정하는 컨트롤도 따로 준비가 되었습니다. (디자인 차암... 한숨나오는..;)
사운드의 볼륨을 설정하고, 바람의 세기도 조절이 가능하죠. (주 : 근데 실제 실행시켜보면 여긴 안되는듯?)
그리고 실험결과 Beta 2 보다는 RTM 버젼에서 좀더 퍼포먼스가 효율적이었습니다. 볼륨을 높이실때 만약 베타 2라면
조심하시길 바랍니다.
(원문 : I noticed the application was a lot less performant on a beta 2 build then on an RTM build. So, if you are
using beta 2 I would recommend caution when increasing the volume of the snow.
RTM버젼을 이 분들은 쓰고 있다는 이야기인가요..)
그럼. 시작해보겠습니다.
1. 새 프로젝트를 생성합니다.
2. 다음 이미지묶음을 다운로드 받습니다. (첨부파일을 다운로드받아주세요)
3. 유저컨트롤을 하나 생성합니다(여기서는 SnowFlake.xaml) 이것을 하려면, Add->New Item...으로 ... (..아시죠?;)
4. 이 SnowFlake.cs를 다음과 같이 코딩합니다.
<UserControl x:Class="Snowflakes.SnowFlake"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Image x:Name="Flake" Source="snowflake.png">
<Image.RenderTransform>
<ScaleTransform x:Name="SnowScale" ScaleX="0.25" ScaleY="0.25"></ScaleTransform>
</Image.RenderTransform>
</Image>
</UserControl>
그냥 이미지 하나를 추가했고, 이 그림이 제가 원하는 것보다 좀 큰 크기였기 때문에, ScaleTransform을 사용해서
1/4 로 줄여주었습니다.
5. 이제 비하인드 코드(SnowFlake.xaml.cs)를 작성해보도록 하겠습니다. 여기엔 이 눈이 떨어지는 로직을
작성할꺼예요.
대충 다음과 같은 방법입니다.
1) 눈이 내리는 효과를 Left, Top 좌표의 변화로 합니다. 이 효과는 50개의 방향전환 중에 하나를 랜덤하게 가집니다.
2) 눈 부스러기의 Top 좌표가 밑에 바닥 좌표와 같아지는 때나 (이 경우에는 764겠죠) 혹은 이게 화면 밖을 벗어날 경우
Completed = true로 둘 것입니다. 메인타이머가 돌면서 Completed가 true인 객체(눈부스러기)들은 치울것입니다.
3) 눈 부스러기가 만들어질 때, Depth 퍼센테이지를 주어서, 랜덤하게 스케일을 키우거나, 작게 할 것입니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Snowflakes
{
public partial class SnowFlake : UserControl
{
double _posLeft = 0.0;
double _posTop = 0.0;
double _floorValue = 764;
int seed = DateTime.Now.Millisecond;
Random _rand = new Random(DateTime.Now.Millisecond);
private bool _completed = false;
double _horzInc = 0.0;
public bool Completed
{
get { return _completed; }
}
public SnowFlake(double left, double top)
{
InitializeComponent();
_posLeft = left;
_posTop = top;
this.SetValue(Canvas.LeftProperty, _posLeft);
this.SetValue(Canvas.TopProperty, _posTop);
Random rndSize = new Random(DateTime.Now.Millisecond);
SnowScale.ScaleX = SnowScale.ScaleY = 0.05 * rndSize.Next(1, 6);
}
public void Fall(double windValue)
{
int value = _rand.Next(50);
if (value == 25) // 1 in 50 change to change direction
{
if (_horzInc >= 0.2)
_horzInc = 0;
else if (_horzInc <= -0.2)
_horzInc = 0;
else
{
value = _rand.Next(3);
if (value == 1) _horzInc = 0.2;
else if (value == 2) _horzInc = -0.2;
else if (value > 0) _horzInc = 0.0;
}
}
double horzValue = _horzInc + (windValue * 0.1);
_posLeft += horzValue;
this.SetValue(Canvas.LeftProperty, _posLeft);
this.SetValue(Canvas.TopProperty, _posTop++);
_completed = (_posLeft >= 1019 || _posLeft <= 0 || _posTop >= _floorValue);
}
}
}
6. 그다음에 Page.xaml.cs에서는, 이 눈 부스러기들을 제어하기 위해서 타이머를 추가합니다.
눈 부스러기들을 움직이고 나서 Completed = true인지 체크할 것입니다.
만약 그렇다면, 지우기 위한 배열 안에 이 객체를 추가하려구요. 부스러기가 만들어지면,
일단은 가장 위쪽에 위치시킬 것입니다.
그런데, 만약 여기 바람이 있다면 바람의 방향에 맞게 움직여주게끔 해야 겠지요.
툴바 제어를 위한 코드까지 포함된 소스입니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Snowflakes
{
public partial class Page : UserControl
{
List<SnowFlake> _snowFlakes = new List<SnowFlake>();
Storyboard _snowflakeTimer = new Storyboard();
Random _rand = new Random(DateTime.Now.Millisecond);
int _newFlakeCount = 2;
int _wind = 0;
public Page()
{
InitializeComponent();
_snowflakeTimer.Duration = TimeSpan.FromMilliseconds(10);
_snowflakeTimer.Completed += new EventHandler(SnowFlakeTimer);
_snowflakeTimer.Begin();
}
private void SnowFlakeTimer(object sender, EventArgs e)
{
MoveSnowFlakes();
CreateSnowFlakes();
}
private void MoveSnowFlakes()
{
List<SnowFlake> _flakesToRemove = new List<SnowFlake>();
foreach (SnowFlake flake in _snowFlakes)
{
flake.Fall(_wind);
if (true == flake.Completed)
_flakesToRemove.Add(flake);
}
foreach (SnowFlake flake in _flakesToRemove)
{
_snowFlakes.Remove(flake);
SnowCanvas.Children.Remove(flake);
}
_snowflakeTimer.Begin();
}
private void CreateSnowFlakes()
{
TotalCount.Text = "Total Snowflakes = " + _snowFlakes.Count;
int count = _rand.Next(0, _newFlakeCount);
for (int i = 0; i < count; i++)
{
SnowFlake flake = new SnowFlake(_rand.Next(0, 1020), 0.0);
_snowFlakes.Add(flake);
SnowCanvas.Children.Add(flake);
}
if (_wind < 0)
{
for (int i = 0; i < count; i++)
{
SnowFlake flake = new SnowFlake(1010, _rand.Next(0, 700));
_snowFlakes.Add(flake);
SnowCanvas.Children.Add(flake);
}
}
else if (_wind > 0)
{
for (int i = 0; i < count; i++)
{
SnowFlake flake = new SnowFlake(0, _rand.Next(0, 700));
_snowFlakes.Add(flake);
SnowCanvas.Children.Add(flake);
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Application.Current.Host.Content.IsFullScreen = true;
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (null != Volume)
{
_newFlakeCount = (int)Volume.Value;
VolumeValue.Text = _newFlakeCount.ToString();
}
}
private void Wind_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (null != Wind)
{
_wind = (int)Wind.Value;
WindValue.Text = _wind.ToString();
}
}
}
}
7. 그리고 마지막으로, 툴바를 포함한 나머지 디자인에 대한 Page.xaml 소스입니다.
<UserControl x:Class="Snowflakes.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="1020" Height="768">
<Canvas x:Name="SnowCanvas" Width="1020" Height="768" Background="Black">
<Image Width="1020" Source="Scene.jpg"></Image>
<TextBlock Canvas.Left="1022" x:Name="TotalCount" Foreground="White">Total Snowflakes</TextBlock>
<TextBlock Canvas.Left="1022" Canvas.Top="30" Foreground="White">Volume</TextBlock>
<Slider x:Name="Volume" Value="3" ValueChanged="Slider_ValueChanged" Canvas.Left="1110"
Canvas.Top="30" Minimum="0" Maximum="10" Width="100"></Slider>
<TextBlock Canvas.Left="1210" Canvas.Top="30" Foreground="White"
x:Name="VolumeValue">2</TextBlock>
<TextBlock Canvas.Left="1022" Canvas.Top="60" Foreground="White">Wind</TextBlock>
<Slider x:Name="Wind" Value="0" ValueChanged="Wind_ValueChanged" Canvas.Left="1110" Canvas.Top="60"
Minimum="-50" Maximum="50" Width="100"></Slider>
<TextBlock Canvas.Left="1210" Canvas.Top="60" Foreground="White" x:Name="WindValue">0</TextBlock>
<Button Canvas.Left="1022" Canvas.Top="100" Content="Full Screen" Click="Button_Click"></Button>
</Canvas>
</UserControl>
이제 여러분들은, 눈내리는 아름다운 광경을 보실 수 있으실꺼예요.
--------------------------------------------------------------------------------------------------------------
그냥 소스 하나 카피한 느낌이네요. 보시는 분들에게 도움이 되셨길..
완성된 소스도 첨부합니다.
[출처] 실버라이트 네이버 카페