这可能是我第一编自己码的文章,也可能会很久才更新,不过作为学习,先分享一下经验吧,展示的代码都是个人写的,如果有觉得写的不好的地方,欢迎指出讨论,共同进步。
首先我会说一下:
1:为什么要开发视频弹幕程序?
因为看到哔哩哔哩(bilibili)网站里的用flash做的弹幕视频吸引了很多眼球,而我也觉得做一个不难,那么我不入地狱谁入地狱呢,于是就自己着手开发。
由于简捷开发,因此也没怎么考虑用框架之类的东西也没有怎么考虑性能等问题,随手新建一个xaml就开始埋头写了。
1:首先是初步界面设计
我还是基于传统的界面进行设计
如上图,一个页面中用Grid划分3个部分,左上为播放视频的播放器,左下为弹幕的基本操作窗口,右边是弹幕列表以及其它操作等等。
2:弹幕发射原理
其实原理很简单,播放器上面加一个Canvas,弹幕就在上面作移动的动画就可以了,由于只弄了从右到左的飞过模式,代码如下。
View Code
private void ShowBarrage(object sender, BarrageShowEventArgs e)
{
foreach (var info in e.NewBarrages)
{
Storyboard story = new Storyboard();
TextBlock text = BarrageBase.CreatTextBox(info);//把文本信息转换为TextBlock各项属性
BarrageCan.Children.Add(text);
Canvas.SetLeft(text, player.ActualWidth - text.ActualWidth / 2);
Canvas.SetTop(text, barTop);
MoveBarTop(text.ActualHeight);//设置文本在Canvas中的高和宽
DoubleAnimation anim = BarrageBase.CreateDoubleAnimation(text, "(Canvas.Left)", player.ActualWidth - text.ActualWidth / 2, -text.ActualWidth,
new Duration(TimeSpan.FromMilliseconds(info.TextSpeed)), null);//定义动画帧
story.Children.Add(anim);
story.Begin();
story.Completed += (s, t) =>
{
if (BarrageCan.Children.Count > 0)
{
BarrageCan.Children.RemoveAt(0);//动画结束后移除
}
};
}
}
{
foreach (var info in e.NewBarrages)
{
Storyboard story = new Storyboard();
TextBlock text = BarrageBase.CreatTextBox(info);//把文本信息转换为TextBlock各项属性
BarrageCan.Children.Add(text);
Canvas.SetLeft(text, player.ActualWidth - text.ActualWidth / 2);
Canvas.SetTop(text, barTop);
MoveBarTop(text.ActualHeight);//设置文本在Canvas中的高和宽
DoubleAnimation anim = BarrageBase.CreateDoubleAnimation(text, "(Canvas.Left)", player.ActualWidth - text.ActualWidth / 2, -text.ActualWidth,
new Duration(TimeSpan.FromMilliseconds(info.TextSpeed)), null);//定义动画帧
story.Children.Add(anim);
story.Begin();
story.Completed += (s, t) =>
{
if (BarrageCan.Children.Count > 0)
{
BarrageCan.Children.RemoveAt(0);//动画结束后移除
}
};
}
}
弹幕实体类代码如下:
View Code
public class BarrageInfo : IComparable<BarrageInfo>
{
public string ShowText { get; set; }
public double TextSpeed = 5000;
public ShowMode Mode { get; set; }
public TimeSpan ShowTime { get; set; }
public string CreatTime { get; set; }
public double BarSize = 20.0;
public FontFamily BarFamily = new FontFamily("Portable User Interface");
public SolidColorBrush BarColor = new SolidColorBrush(Colors.White);
public string PlayTime
{
get { return ShowTime.ToString().Split('.')[0]; }
}
public string FontColor
{
get { return BarColor.Color.ToString().Replace('#',' ').Trim(); }
}
public BarrageInfo(TextBox tbx)
{
BarSize = tbx.FontSize;
BarFamily = tbx.FontFamily;
BarColor = (SolidColorBrush)tbx.Foreground;
ShowText = tbx.Text;
Mode = (ShowMode)Convert.ToInt32(tbx.Tag.ToString());
CreatTime = DateTime.Now.ToString("yyyy'-'MM'-'dd' 'HH':'mm':'ss");
}
public BarrageInfo(JsonValue json)
{
string time = json["ShowTime"];
ShowTime = StringToTimeSpan(time);
BarSize = json["FontSize"];
BarSize = json["FontSize"];
BarFamily = new FontFamily(json["FontFamily"]);
BarColor = BarrageBase.StringToColor(json["Foreground"]);
ShowText = json["ShowText"];
Mode = (ShowMode)((int)json["ShowMode"]);
CreatTime = json["CreatTime"];
}
private TimeSpan StringToTimeSpan(string str)
{
string[] times = str.Split(':');
return new TimeSpan(StringToInt32(times[0]), StringToInt32(times[1]), StringToInt32(times[2]));
}
private int StringToInt32(string str)
{
return Convert.ToInt32(str);
}
public int CompareTo(BarrageInfo other)
{
return ShowTime.CompareTo(other.ShowTime);
}
}
{
public string ShowText { get; set; }
public double TextSpeed = 5000;
public ShowMode Mode { get; set; }
public TimeSpan ShowTime { get; set; }
public string CreatTime { get; set; }
public double BarSize = 20.0;
public FontFamily BarFamily = new FontFamily("Portable User Interface");
public SolidColorBrush BarColor = new SolidColorBrush(Colors.White);
public string PlayTime
{
get { return ShowTime.ToString().Split('.')[0]; }
}
public string FontColor
{
get { return BarColor.Color.ToString().Replace('#',' ').Trim(); }
}
public BarrageInfo(TextBox tbx)
{
BarSize = tbx.FontSize;
BarFamily = tbx.FontFamily;
BarColor = (SolidColorBrush)tbx.Foreground;
ShowText = tbx.Text;
Mode = (ShowMode)Convert.ToInt32(tbx.Tag.ToString());
CreatTime = DateTime.Now.ToString("yyyy'-'MM'-'dd' 'HH':'mm':'ss");
}
public BarrageInfo(JsonValue json)
{
string time = json["ShowTime"];
ShowTime = StringToTimeSpan(time);
BarSize = json["FontSize"];
BarSize = json["FontSize"];
BarFamily = new FontFamily(json["FontFamily"]);
BarColor = BarrageBase.StringToColor(json["Foreground"]);
ShowText = json["ShowText"];
Mode = (ShowMode)((int)json["ShowMode"]);
CreatTime = json["CreatTime"];
}
private TimeSpan StringToTimeSpan(string str)
{
string[] times = str.Split(':');
return new TimeSpan(StringToInt32(times[0]), StringToInt32(times[1]), StringToInt32(times[2]));
}
private int StringToInt32(string str)
{
return Convert.ToInt32(str);
}
public int CompareTo(BarrageInfo other)
{
return ShowTime.CompareTo(other.ShowTime);
}
}
两个构造函数分别转换对应新建的弹幕信息和从服务端获取的弹幕信息。
下一节继续。