Wpf Canvas не выходит за границы - PullRequest
0 голосов
/ 08 октября 2018

c # код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Attempt
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Ellipse e1 = new Ellipse();
        DispatcherTimer t1, t2, t3, t4, t5;
        TimeSpan o = new TimeSpan(0, 0, 0, 0, 10);
        public MainWindow()
        {
            InitializeComponent();
            t1 = new DispatcherTimer();
            t2 = new DispatcherTimer();
            t3 = new DispatcherTimer();
            t4 = new DispatcherTimer();
            t1.Interval = o;
            t2.Interval = o;
            t3.Interval = o;
            t4.Interval = o;
            t1.Tick += T1_Tick;
            t2.Tick += T2_Tick;
            t3.Tick += T3_Tick;
            t4.Tick += T4_Tick;
            myCanvas.Children.Add(e1);
            e1.Fill = new SolidColorBrush(Colors.Black);
            Canvas.SetLeft(e1, 250);
            Canvas.SetTop(e1, 250);
            e1.Height = 75;
            e1.Width = 75;
            this.KeyDown += MainWindow_KeyDown;
            if(Canvas.GetLeft(e1) + e1.Width > myCanvas.Width)
            {
                Canvas.SetLeft(e1, myCanvas.Width);
            }
        }


        //Key.Right
        private void T4_Tick(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            Canvas.SetLeft(e1, Canvas.GetLeft(e1) + 10);
        }


        //Key.Left
        private void T3_Tick(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            Canvas.SetLeft(e1, Canvas.GetLeft(e1) - 10);
        }


        //Key.Up
        private void T2_Tick(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            Canvas.SetTop(e1, Canvas.GetTop(e1) - 10);
        }


        //Key.Down
        private void T1_Tick(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            Canvas.SetTop(e1, Canvas.GetTop(e1) + 10);
        }


        //Shortcut
        public void timer1()
        {
            t1.Start();
            t2.Stop();
            t3.Stop();
            t4.Stop();
        }
        public void timer2()
        {
            t1.Stop();
            t2.Start();
            t3.Stop();
            t4.Stop();
        }
        public void timer3()
        {
            t1.Stop();
            t2.Stop();
            t3.Start();
            t4.Stop();
        }
        public void timer4()
        {
            t1.Stop();
            t2.Stop();
            t3.Stop();
            t4.Start();
        }
        //MainWindow KeyDown
        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            //throw new NotImplementedException();
            if (e.Key == Key.Down && !t2.IsEnabled) 
            {
                timer1();
            }
            if (e.Key == Key.Up && !t1.IsEnabled)
            {
                timer2();
            }
            if (e.Key == Key.Left && !t4.IsEnabled)
            {
                timer3();
            }
            if (e.Key == Key.Right && !t3.IsEnabled)
            {
                timer4();
            }
        }
    }
}

xaml код:

<Window x:Class="Attempt.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:Attempt"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Canvas Name="myCanvas">

    </Canvas>
</Window>

Я пытался создать небольшую «игру», в которой вы можете перемещаться на все 4 стороны (блокируя обратные стороны) и я пытаюсь сделать так, чтобы он не смог поразить холст.По какой-то причине он не читает ничего из того, что я пытаюсь сделать (эта часть):

    if(Canvas.GetLeft(e1) + e1.Width > myCanvas.Width)
    {
        Canvas.SetLeft(e1, myCanvas.Width);
    }

Где я иду не так?Что-то не так с тем, как я справляюсь?Благодарю.(Я пытался решить эту проблему последние полтора часа, и я понятия не имею ... спасибо.)

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

В вашем коде много неправильных вещей, и самое важное, что ваши обработчики тиков никогда не сравнивают фактическое значение Left или Top с какими-либо границами.

Попробуйте эту упрощенную версию:

<Window ... KeyDown="WindowKeyDown">
    <Grid>
        <Canvas x:Name="canvas" Margin="40">
            <Ellipse x:Name="ellipse" Canvas.Left="300" Canvas.Top="200"
                     Width="75" Height="75" Margin="-37.5" Fill="Black"/>
        </Canvas>
    </Grid>
</Window>

с кодом только с одним таймером и обработчиком Tick, который обновляет Left и Top в соответствии с вектором скорости.Новая позиция проверяется относительно нижней границы нуля и верхней границы canvas.ActualWidth / canvas.ActualHeight.

public partial class MainWindow : Window
{
    private Vector speed = new Vector();

    public MainWindow()
    {
        InitializeComponent();

        var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(20) };
        timer.Tick += TimerTick;
        timer.Start();
    }

    private void TimerTick(object sender, EventArgs e)
    {
        var pos = new Point(Canvas.GetLeft(ellipse), Canvas.GetTop(ellipse)) + speed;

        Canvas.SetLeft(ellipse, Math.Min(Math.Max(pos.X, 0), canvas.ActualWidth));
        Canvas.SetTop(ellipse, Math.Min(Math.Max(pos.Y, 0), canvas.ActualHeight));
    }

    private void WindowKeyDown(object sender, KeyEventArgs e)
    {
        speed.X = 0;
        speed.Y = 0;

        switch (e.Key)
        {
            case Key.Left:
                speed.X = -10;
                break;
            case Key.Right:
                speed.X = 10;
                break;
            case Key.Up:
                speed.Y = -10;
                break;
            case Key.Down:
                speed.Y = 10;
                break;
        }
    }
}

Теперь вы можете также реализовать другую стратегию перемещения, добавляя или вычитая компоненты из / из текущеговектор скорости:

private void WindowKeyDown(object sender, KeyEventArgs e)
{
    switch (e.Key)
    {
        case Key.Left:
            speed.X--;
            break;
        case Key.Right:
            speed.X++;
            break;
        case Key.Up:
            speed.Y--;
            break;
        case Key.Down:
            speed.Y++;
            break;
        default:
            speed.X = 0;
            speed.Y = 0;
            break;
    }
0 голосов
/ 08 октября 2018

Использование четырех таймеров не кажется хорошим подходом.Я не видел явной проблемы с производительностью в одном таймере.

Я реализовал игру с вашими движениями, используя один таймер:

Ваша проблема:

1.Вы должны добавить свой оператор if в каждый таймер, чтобы проверять его при необходимости

2. На самом деле это не ваша проблема.myCanvas's Ширина и высота установлены в NaN (не определено), потому что вы их не установили.Вы должны использовать ActualWidth и ActualHeight

    Ellipse e1 = new Ellipse();
    DispatcherTimer t1;
    TimeSpan o = new TimeSpan(0, 0, 0, 0, 10);
    Key Direction { get; set; } = Key.Space;

    public MainWindow()
    {
        InitializeComponent();
        t1 = new DispatcherTimer();
        t1.Interval = o;
        t1.Tick += T1_Tick;

        myCanvas.Children.Add(e1);
        e1.Fill = new SolidColorBrush(Colors.Black);
        Canvas.SetLeft(e1, 250);
        Canvas.SetTop(e1, 250);
        e1.Height = 75;
        e1.Width = 75;

        this.KeyDown += MainWindow_KeyDown;
        t1.Start();
    }

    private void T1_Tick(object sender, EventArgs e)
    {
        double X = Canvas.GetLeft(e1);
        double Y = Canvas.GetTop(e1);

        if (Direction == Key.Up) // Up
        {
            if (Y > 0)
                Canvas.SetTop(e1, Y - 10);
        }
        else if (Direction == Key.Left) // Left
        {
            if (X > 0)
                Canvas.SetLeft(e1, X - 10);
        }
        else if (Direction == Key.Right) // Right
        {
            if (X + e1.ActualWidth < myCanvas.ActualWidth)
                Canvas.SetLeft(e1, X + 10);
        }
        else if (Direction == Key.Down) // Down
        {
            if (Y + e1.ActualHeight < myCanvas.ActualHeight)
                Canvas.SetTop(e1, Y + 10);
        }
    }

    //MainWindow KeyDown
    private void MainWindow_KeyDown(object sender, KeyEventArgs e)
    {
        Direction = e.Key;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...