65.9K
CodeProject 正在变化。 阅读更多。
Home

iPaint

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (8投票s)

2013年8月8日

CPOL

8分钟阅读

viewsIcon

18441

不是普通的绘画应用

引言

绘画很有趣,绘画很有娱乐性,绘画也是社交性的。iPaint 是一种新的绘画方式,iPaint 也是一个音乐作曲家。你不是在绘画,而是在创作绘画。

用途与概念  

iPaint 可以供朋友和家人用于娱乐。

iPaint 的主要功能是绘画,它同样也是一个不错的乐器,这只是一个附带效应。iPaint 的主要目的是让家人和朋友的绘画变得有趣。通过集成“家庭云”,iPaint 将绘画变成家庭绘画。

背景

有很多绘画应用,那么 iPaint 有什么不同之处呢?我鼓励你观看这个 视频,然后你就会有答案。iPaint 旨在提供独特的体验。 

最独特之处在于音乐。你不仅绘画,还可以创作音乐。使用 iPaint 绘画是一种绝佳的体验。

开发方法

目标平台:一体机电脑

类别:娱乐

我正在使用 WPF 构建这个应用程序。我将使用一体机电脑来优化它以适应大屏幕尺寸,并**利用触控笔**作为印章,当在屏幕上按下时,它将在触摸区域填充颜色。

项目状态  

我已经将工作流程分为三个部分。

第一部分 

基本功能将在第一部分完成。

状态:已完成

第二部分 

增加视觉吸引力。增加光泽和铬色。

状态:进行中

第三部分  

增加在线功能。

状态:设计阶段;

未来: 

我计划将其移植到 Unity 并发布到所有平台。由于我还在 Unity 中开发一款游戏,我每天对 Unity 的了解都在增加,我对使用 Unity 构建 iPaint 的信心也随之增强。

Unity 比 WPF 这样的演示框架提供了更强大的功能。Unity 的工作量更大,但你获得的权力也更大。移植到 Unity 是未来的计划,因为这是一项大工程,现在无法完成。如果我尝试,我就会错失良机。
 

特点

  • 简单绘画

    iPaint 提供了一个虚拟画布供您绘画。iPaint 支持多点触控,手指数量没有上限。

  • 颜色填充

    除了传统的绘画功能外,还有颜色填充。iPaint 包含许多素描,用户可以在其中填充颜色。 

  • 参考绘画

    在此模式下,用户会看到一幅参考画,他的任务是复制它。用户可以通过临摹其他优秀画家的作品来学习绘画并培养创造力。

    创新功能

    iPaint 与众不同之处在于以下功能

  • 协作

    你可以与其他人合作一起绘画,无需实体在场即可共同创作。你可以通过互联网使用 iPaint Cloud 进行绘画。

  • iPaint 保存与继续

    你的画作保存在你的设备上,你可以随时继续修改。你也可以锁定一幅画,以防止他人修改或删除。

  • 云存储

    你所有的画作都保存在云端,可以在你的所有设备上访问。你可以在一台设备上开始一幅新画,在另一台设备上继续,然后在另一台完全不同的设备或平台上修改,或者在移动中用手机进行修改!

  • 绘画录制与回放

    观看自己的创作过程!!

    你的画作会被录制并保存,你可以随时回放这些画作,向朋友展示你是如何创作出杰作的,每一笔,每一个颜色,每一段音乐都被录制并回放。

  • 家庭墙 

    通过家庭墙,你可以访问家人的画作,也可以复制任何一位家人的画作并进行修改。通过家庭墙,你可以了解家人在 iPaint 上画了什么。家庭墙充当家庭的社交网络。你还可以在绘画时与家人聊天。

    计划在协作时增加应用内视频通话。

  • 音乐 

    iPaint 将两项最具创造性、最激动人心的任务——绘画和音乐——融为一体。

    你不是在绘画,你是在创作绘画。iPaint 为绘画增添了音乐的触感。当你绘画时,你创作一个音符;当你填充颜色时,你创作一个持续音。这就好像你在一体化地绘画和创作音乐。

    查看 演示,了解 iPaint 中音乐与绘画的融合。

  • 视觉效果

    iPaint 充满了视觉效果,在绘画时能带来平静和成就感。这些视觉效果为在虚拟画布上绘画增添了微妙的质感。这些视觉效果有助于建立成就感,因为最终的画作无论用户的绘画技巧如何,都会很漂亮。

  • 动态色彩

    颜色是动态的,当你绘画时,颜色会美妙地变化,创作出杰作。

    下面是一幅用 iPaint 原型和动态颜色绘制的画。颜色在任何时候都没有手动更改过,全都是动态的。 

  • 滑移颜色填充  

    你不需要频闪器来填充颜色。只需将屏幕按住你想填充颜色的点,颜色就会像从你的手指流到屏幕一样在屏幕上扩散。

  • 直观的颜色选择器 

    在 iPaint 中改变颜色非常方便。调色板是一个带滑块的圆形管。你滑动管子来选择所需的颜色。

  • 128 种乐器

    iPaint 有大约 128 种乐器可供选择。从大钢琴到电吉他,iPaint 应有尽有。

使用特定于平台的特色功能 
  • 触控笔

    触控笔用于填充颜色甚至绘画。

  • 27 英寸大尺寸触摸屏

    一体机电脑的大尺寸提供了宽阔的绘画区域。

    iPaint 利用宽阔的屏幕尺寸提供了一个大的画布,并支持多点触控。同时绘画的人数没有限制。

  • 环绕声扬声器

    高品质的环绕声扬声器将产生优美的音乐。对用户的耳朵有益;)

演示  

使用代码

绘画应用有三个主要功能。

  • 绘画
  • 播放声音
  • 处理社交功能

绘画代码

在画布上绘制线条。

我使用路径来绘制线条。

你可以查看 这个 教程,了解如何构建一个简单的绘画应用。代码是从那里获取的。我已根据我的需要进行了修改。

    private PathFigure _pathFigure;  // the list of stroke points
    private bool _isOnCanvas;
    private Path _path = new Path();
    private Color _color = Colors.Black;


    private const float _penWidth = 3.0f;    // pen width for drawing the stroke

    /// 
    /// Seal the object.
    /// 
    /// 
    /// To improve performance, Seal replaces the list with fixed array.
    /// 
    public void Freeze()
    {
        if (_pathFigure != null)
            _pathFigure.Freeze();
    }

    /// 
    /// Indicate if we can add nore points to the stroke
    /// 
    public bool IsFrozen
    {
        get
        {
            return _pathFigure.IsFrozen;
        }
    }

    /// 
    ///  Add the complete stroke
    /// 
    /// the canvas that hold all figures
    public void AddToCanvas(Canvas canvas)
    {
        if (_isOnCanvas)
            return;
        _isOnCanvas = true;

        PathGeometry pathGeometry = new PathGeometry();
        pathGeometry.Figures = new PathFigureCollection() { _pathFigure };
        _path.StrokeThickness = _penWidth;
        _path.Data = pathGeometry;
        canvas.Children.Add(_path);
    }


    /// 
    /// Access to the property stroke color
    /// 
    public Color Color
    {
        get
        {
            return _color;
        }
        set
        {
            _color = value;
            _path.Stroke = new SolidColorBrush(_color);
        }
    }


    /// 
    /// Access to the property stroke ID 
    /// 
    public int Id { get; set; }

    /// 
    /// Adds a point to the stroke.
    /// 
    /// point to be added to the stroke
    public void Add(Point pt)
    {
        if (_pathFigure != null && IsFrozen)
            throw new InvalidOperationException("This object is frozen");

        if (_pathFigure == null)
        {
            _pathFigure = new PathFigure();
            _pathFigure.IsClosed = false;
            _pathFigure.StartPoint = pt;
            _pathFigure.Segments = new PathSegmentCollection();
        }
        else
        {
            _pathFigure.Segments.Add(new LineSegment(pt, true));
        }
    }

播放声音的代码

我使用 MIDI for .NET 库来播放声音。我在新线程中播放每个音符,以便多个音符可以同时播放。我让线程休眠一秒钟,然后关闭 MIDI 播放器,这样音符就会播放一秒钟然后关闭。

MDI for .NET 提供了一个 MidiPlayer 类型的静态对象,你用它来播放声音。在播放任何声音之前,你必须先打开 MIDI 播放器。你可以通过调用 MidiPlayer.OpenMidi() 来做到这一点。默认情况下,MidiPlayer 带有 127 个通道(乐器)。程序更改用于更改通道、音量等。你通过调用 play 和一个 NoteOn 对象来播放音符,其中 NoteOn 对象包含一个 delta(初始延迟)、通道(一个字节值)、音符(一个字符串,如“C0”)和音量(一个字节值)。

  new Thread(() =>
            {
                MidiPlayer.OpenMidi();
                MidiPlayer.Play(new ProgramChange(0, 1, channel));
                MidiPlayer.Play(wheel);
                MidiPlayer.Play(new NoteOn(delta, 1, note, vol));
                Thread.Sleep(1000);
                MidiPlayer.Play(new NoteOff(delta, 1, note, vol));
                MidiPlayer.CloseMidi();
            }).Start();

处理社交功能的代码

我使用 SignalR 进行通信,并将绘画推送到连接的成员。SignalR 需要托管在某个地方才能工作。我使用 Windows Azure 来托管 SignalR,并作为所有绘画的云存储。

我将绘画保存在 XML 中,存储所有播放过的点、颜色和音乐的时间线,这些数据稍后会被上传到服务器或用于回放绘画。

构建主页。

主页是一个绘画作品的幻灯片。构建背景很有趣。


背景是由许多带有随机颜色的椭圆堆叠在一起形成的,以产生模糊生动的背景。构建该背景的代码。

椭圆绘制在名为“CanvasBackground”的画布上。

 int x=-30,y=-30;
            for (int i = 0; i < width/15*width/30; i++)
            {
                    Ellipse ellipse = new Ellipse();
                    ellipse.Width = ellipse.Height = (width / 30) - radiusRandom.Next(0, height / 100);
                    ellipse.Fill = GetRandomColor();
                    ellipse.Opacity =0.7;
                    ellipse.Effect = new BlurEffect() { Radius = 15 };
                    Canvas.SetTop(ellipse, y);
                    Canvas.SetLeft(ellipse, x);
                    _backgroundCircles[i]=(ellipse);
                    CanvasBackground.Children.Add(ellipse);
                    x = x + width / 90;
                    if (x > width)
                    {
                        x = -30;
                        y = y + height / 20;
                    }
                    if (y > height)
                        y = 0;
            }

为了让事情变得有趣,我对背景做了一些动画。通过随机选择一些椭圆,我改变它们的颜色、不透明度或模糊度,这使得背景动态而不是无聊的静态。代码:我使用一个 DispatchTimer 每 100 秒滴答一次。

        private void animateBackground(object sender, EventArgs e)
        {
            while (currentStack.Count <= 10)
            {
                currentStack.Add(_backgroundCircles[ellipseRandom.Next(_backgroundCircles.Length)]);
            }
            foreach (Ellipse ellipse in currentStack)
            {
                AnimateEllipse(ellipse);
            }
            if (removelRanodm.Next(10) == 2)
            {
                currentStack.RemoveAt(removelRanodm.Next(10));
            }
        }

        private void AnimateEllipse(Ellipse ellipse)
        {
            int what = funtcionRandom.Next(3);

            switch (what)
            {
                case 0:
                    ellipse.Fill = GetRandomColor();
                    break;
                case 1:
                    ellipse.Opacity = opacityRandom.Next(10) / 10f;
                    break;
                case 2:
                    BlurEffect effect = ellipse.Effect as BlurEffect;
                    effect.Radius = radiusRandom.Next(20) / 20f;
                    break;
                default:
                    break;
            }
        }

还有一点,由于椭圆数量众多,加载主页需要一些时间。我的做法是在后台加载页面,同时显示另一个启动屏幕。我使用一个隐藏了导航栏的 NavigationWindow。

后台加载页面的代码。
Page thePage=(Page)Application.LoadComponent(new Uri("/Pages/Home.xaml", UriKind.Relative));  Action action = () =>
           {
              ((NavigationWindow)Application.Current.MainWindow).Navigate(thePage);
               if (MainNavigationWindow != null) MainNavigationWindow.ShowsNavigationUI = false;
           };
            Application.Current.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal);

关注点

在开发这款应用时,我发现自己不是一个音乐家。我试图同时处理很多音符,直到我意识到我做不到,用户也做不到。我将音符数量从 600 个减少到 300 个。我一开始不太愿意这样做,但出乎意料的是,这增加了乐趣。

历史

[2013.07.28] - iMuzik 诞生时带有某些绘画效果,但未能保留。

[2013.07.29] - 改进了音符,去掉了刺耳的音符。

[2013.07.30] - 将音乐应用转变为绘画应用。iPaint 诞生。

[2013.07.31] - 添加了家庭墙,并将 iPaint 转变为家庭应用。

[2013.08.01] - 添加了一些不错的绘画效果,如火花、滑移。

[2013.08.02] - 提高了应用的性能。减少了内存和 CPU 消耗。

[2013.09.01] - 原型完成。

© . All rights reserved.