1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GraphicsLibrary SkiaSharp「Mystify」

Last updated at Posted at 2025-01-22

M.S.社のMystifyスクリーンセーバのSkiaSharp WPF版。
・だんだん崩れるので展開後、指定秒後に再描画してます。

1.キー操作説明

  • [F]...................フルスクリーン表示。(起動直後にFキー)

  • [PageUp].....間隔増 一辺が10の線で構成されているがその線同士の間隔可変

  • [PageDw].....間隔減

  • [マウス左]....再描画(リセット)

  • [マウス右]....終了

2.動画 YouTube

3.コードについて

・非同期で表示本数を可変させてます。
( _=Task.RUN() MainPaintSurface()内の表示For値)
・意外と簡単に出来ました。他にも色んな手法があるので作ってみて下さい。

4.WPF Sourcecode


/////////////////////////////////////////////////////////////////////////////////////
// Mystify LineDemo WPF+SkiaSharp (skiasharp from nuget install)
// MOUSE_RIGHT...Exit,LEFT...RESTART / [PageUp,Down]...Width CHG / [F]...FullSCREEN.
// (c)inf102 S.H. 2024.
/////////////////////////////////////////////////////////////////////////////////////

using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Threading.Tasks;
using System.Windows;

namespace SkiaSharpSample {

    public partial class MainWindow : Window	{

        ///////////////////////////////////////////////////////////////////
        const   int WAIT=15;                        // 画面更新間隔(mmSec) 2以上
        static  int L_WIDTH=1;                      // 線と線の幅 PgUP/DOWN で可変
        const   int EXT=6;                          // 線の伸び  一回の更新で伸ばすドット数 少ないと滑らかに増えるが遅くなる
        const   int THICK=1;                        // 線の太さ 2以上は重くなる
        const   int MAINTAIN = 10000;               // 10本引かれた後、その状態を維持する時間(mmSec)
        const   int INC_DEC=140;                    // 1~10本の線を引く間隔(mmSec)
        ///////////////////////////////////////////////////////////////////
        
        const  int MAX_LINE=40;
        static int LD1=0;
        static int LD2=10;
        static int LD3=20;
        static int LDFLG=0;

        // SKIA_LINEDATA
        static SKPaint A_LINE= new SKPaint{
	        Style =  SKPaintStyle.Stroke,
			IsAntialias=true,
            StrokeWidth = THICK
        };
               
        static bool FULL_SCREEN=false;

        // キャンパスサイズ
        static int CAX,CAY;
                   
        // 表示データ クラス
        DSet[] Line_data= new DSet[2];  
        
		public MainWindow()		{
			InitializeComponent();
            
            // 四角
            Line_data[0]=new DSet();
                            
            // 三角
            Line_data[1]=new DSet();
            
        }

        // 表示データ格納クラス
        public class DSet {

            public struct POINT_XY{
                public int START_X,START_Y; // 開始位置
                public int L;               // 開始位置からの半径
                public int RAG;             // 開始位置からの角度
                public int CUR_X,CUR_Y;     // 現在位置
            }
            public  POINT_XY[] XYDATA= new POINT_XY[MAX_LINE];

            public void Dx(){

                System.Threading.Thread.Sleep(1);
                Random rnd = new Random(DateTime.Now.Millisecond);

                int XY,RA;

                ///////////////////////////////////
                RA=rnd.Next(0,360);
 
                if (CAY<CAX ) XY=rnd.Next(CAY/2,CAX/2);
                else XY=rnd.Next(CAX/2,CAY/2);

                for (int d=0;d<10;d++){
                    XYDATA[d].L=1;
                    XYDATA[d].RAG = RA++;
                    XYDATA[d].START_X = XY-25;
                    XYDATA[d].START_Y = XY-110;
                }

                ///////////////////////////////////
                RA=rnd.Next(0,360);
                
                if (CAY<CAX ) XY=rnd.Next(CAY/2,CAX/2);
                else XY=rnd.Next(CAX/2,CAY/2);
                              
                for (int d=10;d<20;d++){
                    XYDATA[d].L=1;
                    XYDATA[d].RAG = RA++;
                    XYDATA[d].START_X = XY-25;
                    XYDATA[d].START_Y = XY-110;
                }
                
                //////////////////////////////////
                RA=rnd.Next(0,360);
            
                if (CAY<CAX ) XY=rnd.Next(CAY/2,CAX/2);
                else XY=rnd.Next(CAX/2,CAY/2);
            
                for (int d=20;d<30;d++){
                    XYDATA[d].L=1;
                    XYDATA[d].RAG = RA++;
                    XYDATA[d].START_X = XY-25;
                    XYDATA[d].START_Y = XY-110;
                }
   
                ////////////////////////////////
                RA=rnd.Next(0,360);
               
                if (CAY<CAX ) XY=rnd.Next(CAY/2,CAX/2);
                else XY=rnd.Next(CAX/2,CAY/2);
               
                for (int d=30;d<40;d++){
                    XYDATA[d].L=1;
                    XYDATA[d].RAG = RA++;
                    XYDATA[d].START_X = XY-25;
                    XYDATA[d].START_Y = XY-110;
                }
                ////////////////////////////////
            }
        }

        private async void Window_Loaded(object sender, RoutedEventArgs e) {
            _=Task.Run ( ()=> {
                while (true){
                    System.Threading.Thread.Sleep (INC_DEC);
                    if (LDFLG == 0){
                        LD1++;
                        LD2++;
                        LD3++;
                    }
                    if (LDFLG == 2) {
                        LD1--;
                        LD2--;
                        LD3--;
                    }

                    // 0本になった
                    if(LD1<=0 && LDFLG == 2) {
                        LD1=0;
                        LD2=10;
                        LD3=20;
                        LDFLG=0;
                        Line_data[0].Dx();
                        Line_data[1].Dx();
                    }

                    // 10本引かれた
                    if(LD1>=10 && LDFLG == 0) {
                        System.Threading.Thread.Sleep (MAINTAIN);
                        LD1=10;
                        LD2=20;
                        LD3=30;
                        LDFLG=2;
                    }
                }
            });

            // MAIN_LOOP
            while(true){
                await Task.Delay (WAIT);
               
                // 表示データ更新、衝突判定
                Col();

                // 描画
                MainCanvas.InvalidateVisual(); 
            }
        }

        // 衝突判定
        void Col(){
            // 次の表示位置算出
            for (int x=0;x<MAX_LINE;x++){        
                for (int m=0;m<2;m++){
                    Line_data[m].XYDATA[x].CUR_X= (int)(Line_data[m].XYDATA[x].START_X+ Line_data[m].XYDATA[x].L*Math.Sin(Line_data[m].XYDATA[x].RAG*Math.PI/180));
                    Line_data[m].XYDATA[x].CUR_Y= (int)(Line_data[m].XYDATA[x].START_Y- Line_data[m].XYDATA[x].L*Math.Cos(Line_data[m].XYDATA[x].RAG*Math.PI/180));
                }

            }

            // 壁衝突判定 衝突の場合は新たな反射角等を設定
            for (int x=0;x<MAX_LINE;x++){
                for (int m=0;m<2;m++){
                    // 上 up
                    if (Line_data[m].XYDATA[x].CUR_Y <= 0){
                        Line_data[m].XYDATA[x].L=1;
                        Line_data[m].XYDATA[x].RAG=180-Line_data[m].XYDATA[x].RAG;
                        Line_data[m].XYDATA[x].START_Y=Line_data[m].XYDATA[x].CUR_Y;
                        Line_data[m].XYDATA[x].START_X=Line_data[m].XYDATA[x].CUR_X;            
                    }
               
                    // 下 down
                    if (Line_data[m].XYDATA[x].CUR_Y >= CAY){
                        Line_data[m].XYDATA[x].L=1;
                        Line_data[m].XYDATA[x].RAG=180-Line_data[m].XYDATA[x].RAG;
                        Line_data[m].XYDATA[x].START_Y=Line_data[m].XYDATA[x].CUR_Y;
                        Line_data[m].XYDATA[x].START_X=Line_data[m].XYDATA[x].CUR_X;
                    }
                    
                    // 右 right
                    if (Line_data[m].XYDATA[x].CUR_X >= CAX){
                        Line_data[m].XYDATA[x].L=1;
                        Line_data[m].XYDATA[x].RAG=360-Line_data[m].XYDATA[x].RAG;
                        Line_data[m].XYDATA[x].START_Y=Line_data[m].XYDATA[x].CUR_Y;
                        Line_data[m].XYDATA[x].START_X=Line_data[m].XYDATA[x].CUR_X;
                    }
                      
                    // 左 left
                    if (Line_data[m].XYDATA[x].CUR_X <= 0){
                        Line_data[m].XYDATA[x].L=1;
                        Line_data[m].XYDATA[x].RAG=360-Line_data[m].XYDATA[x].RAG;
                        Line_data[m].XYDATA[x].START_Y=Line_data[m].XYDATA[x].CUR_Y;
                        Line_data[m].XYDATA[x].START_X=Line_data[m].XYDATA[x].CUR_X;
                    }

                    // 線を伸ばす
                    Line_data[m].XYDATA[x].L+=EXT;

                }
            }
        }
        
        // WindowSize CHG
        private void skiaCanvas_SizeChanged(object sender, SizeChangedEventArgs e) {
            Line_data[0].Dx();
            Line_data[1].Dx();
        }

        // MOUSE L-BUTTON. RESET
        private void MainCanvas_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
            Line_data[0].Dx();
            Line_data[1].Dx();
        }
         
        // MOUSE R-BUTTON. EXIT
        private void MainCanvas_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
            Application.Current.Shutdown();
        }

        private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {

            // FULL SCREEN
            if (e.Key == System.Windows.Input.Key.F) {
                if (FULL_SCREEN == false){
                    FULL_SCREEN=!FULL_SCREEN;
                    this.WindowStyle = WindowStyle.None;
                    this.WindowState = WindowState.Maximized;
                    Line_data[0].Dx();
                    Line_data[1].Dx();
                    return;
                }
                else {
                    FULL_SCREEN=!FULL_SCREEN;
                    this.WindowStyle = WindowStyle.SingleBorderWindow;
                    this.WindowState = WindowState.Normal;
                    this.Height=600;
                    this.Width=1000;
                    Line_data[0].Dx();
                    Line_data[1].Dx();
                }
            }

            if (e.Key == System.Windows.Input.Key.PageUp) {
                L_WIDTH++;
                Line_data[0].Dx();
                Line_data[1].Dx();
            }

            if (e.Key == System.Windows.Input.Key.PageDown) {
                L_WIDTH--;
                if (L_WIDTH <=0 ) L_WIDTH=1;
                Line_data[0].Dx();
                Line_data[1].Dx();
            }
        }
        
        // 描画
        void MainPaintSurface(object sender, SKPaintSurfaceEventArgs args){
            CAX=args.Info.Width;
            CAY=args.Info.Height;

            Random rnd = new System.Random();
            args.Surface.Canvas.Clear(SKColors.Black);
            
            for (int x=0;x<MAX_LINE;x++) {
                // 四角
                A_LINE.Color=new SKColor((byte)rnd.Next(180,255),(byte)rnd.Next(100,200),(byte)rnd.Next(100,200));
                for(int xx = 0; xx < LD1;xx++)  
                    args.Surface.Canvas.DrawLine(Line_data[0].XYDATA[xx].CUR_X, Line_data[0].XYDATA[xx].CUR_Y, Line_data[0].XYDATA[xx+10].CUR_X, Line_data[0].XYDATA[xx+10].CUR_Y, A_LINE);
               
                A_LINE.Color=new SKColor((byte)rnd.Next(100,200),(byte)rnd.Next(180,255),(byte)rnd.Next(100,200));
                for(int xx = 10; xx < LD2; xx++) 
                    args.Surface.Canvas.DrawLine(Line_data[0].XYDATA[xx].CUR_X, Line_data[0].XYDATA[xx].CUR_Y, Line_data[0].XYDATA[xx+10].CUR_X, Line_data[0].XYDATA[xx+10].CUR_Y, A_LINE);
                                
                A_LINE.Color=new SKColor((byte)rnd.Next(100,200),(byte)rnd.Next(100,200),(byte)rnd.Next(180,255));
                for(int xx = 0; xx < LD1; xx++)
                    args.Surface.Canvas.DrawLine(Line_data[0].XYDATA[xx].CUR_X, Line_data[0].XYDATA[xx].CUR_Y, Line_data[0].XYDATA[xx+30].CUR_X, Line_data[0].XYDATA[xx+30].CUR_Y, A_LINE);
          
                A_LINE.Color=new SKColor((byte)rnd.Next(50,255),(byte)rnd.Next(50,255),(byte)rnd.Next(50,255));
                for(int xx = 20; xx < LD3; xx++)
                    args.Surface.Canvas.DrawLine(Line_data[0].XYDATA[xx].CUR_X, Line_data[0].XYDATA[xx].CUR_Y, Line_data[0].XYDATA[xx+10].CUR_X, Line_data[0].XYDATA[xx+10].CUR_Y, A_LINE);

               
                // 三角
                A_LINE.Color=new SKColor((byte)rnd.Next(00,255),(byte)rnd.Next(00,255),(byte)rnd.Next(0,255));
                for(int xx = 0; xx < LD1; xx++)
                    args.Surface.Canvas.DrawLine(Line_data[1].XYDATA[xx].CUR_X, Line_data[1].XYDATA[xx].CUR_Y,Line_data[1].XYDATA[xx+10].CUR_X, Line_data[1].XYDATA[xx+10].CUR_Y, A_LINE);
               
                A_LINE.Color=new SKColor((byte)rnd.Next(00,255),(byte)rnd.Next(0,255),(byte)rnd.Next(00,255));
                for(int xx = 10; xx < LD2; xx++)
                    args.Surface.Canvas.DrawLine(Line_data[1].XYDATA[xx].CUR_X, Line_data[1].XYDATA[xx].CUR_Y,Line_data[1].XYDATA[xx+10].CUR_X, Line_data[1].XYDATA[xx+10].CUR_Y, A_LINE);                             
              
                A_LINE.Color=new SKColor((byte)rnd.Next(00,255),(byte)rnd.Next(00,255),(byte)rnd.Next(0,255));
                for(int xx = 0; xx < LD1; xx++)
                    args.Surface.Canvas.DrawLine(Line_data[1].XYDATA[xx].CUR_X, Line_data[1].XYDATA[xx].CUR_Y,Line_data[1].XYDATA[xx+20].CUR_X, Line_data[1].XYDATA[xx+20].CUR_Y, A_LINE);
                

            }
        }
    }
}
          

5.WPF XAML

<Window x:Class="SkiaSharpSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SkiaSharpSample" xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF" 
        xmlns:wpf="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF" mc:Ignorable="d"
        Title="LineDemo WPF+SkiaSharp. PageUp,Down=SpaceChenage , MOUSE-LEFT=Resart , RIGHT=Shitdown ,F=FullScreen" Loaded="Window_Loaded" Height="800" Width="1200"  KeyDown="Window_KeyDown" >

    <Grid  >
        <wpf:SKElement x:Name="MainCanvas" PaintSurface="MainPaintSurface" Grid.Column="0" Grid.Row="0" SizeChanged="skiaCanvas_SizeChanged" PreviewMouseLeftButtonDown="MainCanvas_PreviewMouseLeftButtonDown" PreviewMouseRightButtonDown="MainCanvas_PreviewMouseRightButtonDown" />
    </Grid>

</Window>
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?