The Windows Phone Application Werewolf Online has a new server running on. (Thanks to MS Azure) The application has been rebuilt (IP-Address was static in code, but isn’t anymore) and will be in the store every minute. Enjoy
Browser + Razor = Blazor!
Haven’t heard of WebAssemblies yet? Check some other articles to shortly educate yourself about WebAssemblies before continue reading. Ok, but what about C#? As far as my research did take place, there is currently Mono and Microsoft working on a project (Experimental). Since the Mono Project on GitHub lacks too much guidance and I haven’t the power …
Building a performant Hololens Project with Unity
Building performant applications for embedded systems can be quite challenging. In case of the Hololens, we are dealing with a relatively small amount of RAM and GPU power. (Hololens Graphics) Unity is a great tool to build applications real quick without spending much time on the real basics. Hence, Unity already delivers a pre-defined set of …
AABB Collision Detection with Intersection Points (Incl. Rotation)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
public struct Line { public Vector2 a; public Vector2 b; public Line(float x1, float y1, float x2, float y2) { a = new Vector2(x1, y1); b = new Vector2(x2, y2); } public void Rotate(float rad, Vector2 center) { Rotate(rad, ref a, center); Rotate(rad, ref b, center); } private void Rotate(float rad, ref Vector2 point, Vector2 center) { point = Vector2.Transform(point - center, Matrix.CreateRotationZ(rad)) + center; } public bool Intersect(Line line, out Vector2? intersectionPoint) { intersectionPoint = null; float a1 = b.Y - a.Y; float b1 = a.X - b.X; float c1 = a1 * a.X + b1 * a.Y; float a2 = line.b.Y - line.a.Y; float b2 = line.a.X - line.b.X; float c2 = a2 * line.a.X + b2 * line.a.Y; //If the lines are parallel, no collision possible. float det = a1 * b2 - a2 * b1; if (det == 0) return false; float x = (b2 * c1 - b1 * c2) / det; float y = (a1 * c2 - a2 * c1) / det; if (OnLine(this, x, y) && OnLine(line, x, y)) { intersectionPoint = new Vector2(x, y); return true; } return false; } public static bool OnLine(Line line, float x, float y) { return Math.Min(line.a.X, line.b.X) <= x && x <= Math.Max(line.a.X, line.b.X) && Math.Min(line.a.Y, line.b.Y) <= y && y <= Math.Max(line.a.Y, line.b.Y); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
public struct SRectangle { public Line left; public Line top; public Line right; public Line bottom; public void Rotate(float rad, Vector2 center) { left.Rotate(rad, center); top.Rotate(rad, center); right.Rotate(rad, center); bottom.Rotate(rad, center); } public static SRectangle FromRectangle(Rectangle rectangle, Vector2 origin, float rotation) { Line left = new Line(rectangle.X, rectangle.Y, rectangle.X, rectangle.Y + rectangle.Height); Line top = new Line(rectangle.X, rectangle.Y, rectangle.X + rectangle.Width, rectangle.Y); Line right = new Line(rectangle.X + rectangle.Width, rectangle.Y, rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); Line bottom = new Line(rectangle.X, rectangle.Y + rectangle.Height, rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); left.a.X -= origin.X; left.a.Y -= origin.Y; left.b.X -= origin.X; left.b.Y -= origin.Y; top.a.X -= origin.X; top.a.Y -= origin.Y; top.b.X -= origin.X; top.b.Y -= origin.Y; right.a.X -= origin.X; right.a.Y -= origin.Y; right.b.X -= origin.X; right.b.Y -= origin.Y; bottom.a.X -= origin.X; bottom.a.Y -= origin.Y; bottom.b.X -= origin.X; bottom.b.Y -= origin.Y; origin.X += rectangle.X - rectangle.Width / 2; origin.Y += rectangle.Y - rectangle.Height / 2; left.Rotate(rotation, origin); right.Rotate(rotation, origin); top.Rotate(rotation, origin); bottom.Rotate(rotation, origin); return new SRectangle() { left = left, right = right, top = top, bottom = bottom }; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public static bool AABB_AABB(SmartRectangle x, SmartRectangle y, out Vector2[] collisionPoints) { List<Vector2> cp = new List<Vector2>(); /* Left against y */ if (x.left.Intersect(y.left, out Vector2? llcp)) cp.Add(llcp.Value); if (x.left.Intersect(y.top, out Vector2? ltcp)) cp.Add(ltcp.Value); if (x.left.Intersect(y.right, out Vector2? lrcp)) cp.Add(lrcp.Value); if (x.left.Intersect(y.bottom, out Vector2? lbcp)) cp.Add(lbcp.Value); /* Top against y */ if (x.top.Intersect(y.left, out Vector2? tlcp)) cp.Add(tlcp.Value); if (x.top.Intersect(y.top, out Vector2? ttcp)) cp.Add(ttcp.Value); if (x.top.Intersect(y.right, out Vector2? trcp)) cp.Add(trcp.Value); if (x.top.Intersect(y.bottom, out Vector2? tbcp)) cp.Add(tbcp.Value); /* Right against y */ if (x.right.Intersect(y.left, out Vector2? rlcp)) cp.Add(rlcp.Value); if (x.right.Intersect(y.top, out Vector2? rtcp)) cp.Add(rtcp.Value); if (x.right.Intersect(y.right, out Vector2? rrcp)) cp.Add(rrcp.Value); if (x.right.Intersect(y.bottom, out Vector2? rbcp)) cp.Add(rbcp.Value); /* Bottom against y */ if (x.bottom.Intersect(y.left, out Vector2? blcp)) cp.Add(blcp.Value); if (x.bottom.Intersect(y.top, out Vector2? btcp)) cp.Add(btcp.Value); if (x.bottom.Intersect(y.right, out Vector2? brcp)) cp.Add(brcp.Value); if (x.bottom.Intersect(y.bottom, out Vector2? bbcp)) cp.Add(bbcp.Value); collisionPoints = cp.ToArray(); return cp.Count > 0; } |
Switching to Linux – Roadmap 🎬 1
Since Window 8.0 has been released I thought about switching to Linux due many different reasons, whichever I won’t cover in this article. However, the idea to try Linux was always present and the desire to do so, grew from day to day. Long story short, due Driver problems Nearly none-existing games Lacking productivity tools Missing …
WPF Scrollable + Zoomable + Dragable Control
Unluckily there is no standard control to zoom, drag and scroll your content. My implementation is based on following tutorial. With this implementation you are able to zoom, drag and scroll arbitrary controls. Showcase ScrollDragZoomControl.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<UserControl x:Class="MinimalMonitoringClient.Controls.ScrollDragZoomControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="Transparent"> <UserControl.Template> <ControlTemplate TargetType="UserControl"> <ScrollViewer x:Name="scrollViewer" Loaded="scrollViewer_Loaded" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"> <Grid Name="grid" RenderTransformOrigin="0.5,0.5"> <Grid.LayoutTransform> <TransformGroup> <ScaleTransform x:Name="scaleTransform" /> </TransformGroup> </Grid.LayoutTransform> <Viewbox> <!-- Present the actual stuff the user wants to display --> <ContentPresenter /> </Viewbox> </Grid> </ScrollViewer> </ControlTemplate> </UserControl.Template> </UserControl> |
ScrollDragZoomControl.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace NAMESPACE { /// <summary> /// Interaktionslogik für ScrollDragZoomControl.xaml /// </summary> public partial class ScrollDragZoomControl : UserControl { private int zoomLevel = 1; private ScaleTransform scaleTransform; private ScrollViewer scrollViewer; private Grid grid; Point? lastCenterPositionOnTarget; Point? lastMousePositionOnTarget; Point? lastDragPoint; public ScrollDragZoomControl() { InitializeComponent(); } private void scrollViewer_Loaded(object sender, RoutedEventArgs e) { scaleTransform = (ScaleTransform)Template.FindName("scaleTransform", this); scrollViewer = (ScrollViewer)Template.FindName("scrollViewer", this); grid = (Grid)Template.FindName("grid", this); scrollViewer.ScrollChanged += OnScrollViewerScrollChanged; scrollViewer.MouseLeftButtonUp += OnMouseLeftButtonUp; scrollViewer.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp; scrollViewer.PreviewMouseWheel += OnPreviewMouseWheel; scrollViewer.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown; scrollViewer.MouseMove += OnMouseMove; } void OnMouseMove(object sender, MouseEventArgs e) { if (lastDragPoint.HasValue) { Point posNow = e.GetPosition(scrollViewer); double dX = posNow.X - lastDragPoint.Value.X; double dY = posNow.Y - lastDragPoint.Value.Y; lastDragPoint = posNow; scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - dX); scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - dY); } } void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var mousePos = e.GetPosition(scrollViewer); if (mousePos.X <= scrollViewer.ViewportWidth && mousePos.Y < scrollViewer.ViewportHeight) //make sure we still can use the scrollbars { scrollViewer.Cursor = Cursors.SizeAll; lastDragPoint = mousePos; Mouse.Capture(scrollViewer); } } void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { lastMousePositionOnTarget = Mouse.GetPosition(grid); if (e.Delta > 0) zoomLevel++; else if (e.Delta < 0) zoomLevel--; zoomLevel = zoomLevel < 1 ? 1 : zoomLevel; scaleTransform.ScaleX = zoomLevel; scaleTransform.ScaleY = zoomLevel; var centerOfViewport = new Point(scrollViewer.ViewportWidth / 2, scrollViewer.ViewportHeight / 2); lastCenterPositionOnTarget = scrollViewer.TranslatePoint(centerOfViewport, grid); e.Handled = true; } void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { scrollViewer.Cursor = Cursors.Arrow; scrollViewer.ReleaseMouseCapture(); lastDragPoint = null; } void OnScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e) { if (e.ExtentHeightChange != 0 || e.ExtentWidthChange != 0) { Point? targetBefore = null; Point? targetNow = null; if (!lastMousePositionOnTarget.HasValue) { if (lastCenterPositionOnTarget.HasValue) { var centerOfViewport = new Point(scrollViewer.ViewportWidth / 2, scrollViewer.ViewportHeight / 2); Point centerOfTargetNow = scrollViewer.TranslatePoint(centerOfViewport, grid); targetBefore = lastCenterPositionOnTarget; targetNow = centerOfTargetNow; } } else { targetBefore = lastMousePositionOnTarget; targetNow = Mouse.GetPosition(grid); lastMousePositionOnTarget = null; } if (targetBefore.HasValue) { double dXInTargetPixels = targetNow.Value.X - targetBefore.Value.X; double dYInTargetPixels = targetNow.Value.Y - targetBefore.Value.Y; double multiplicatorX = e.ExtentWidth / grid.Width; double multiplicatorY = e.ExtentHeight / grid.Height; double newOffsetX = scrollViewer.HorizontalOffset - dXInTargetPixels * multiplicatorX; double newOffsetY = scrollViewer.VerticalOffset - dYInTargetPixels * multiplicatorY; if (double.IsNaN(newOffsetX) || double.IsNaN(newOffsetY)) { return; } scrollViewer.ScrollToHorizontalOffset(newOffsetX); scrollViewer.ScrollToVerticalOffset(newOffsetY); } } } } } |
Usage Add the “ScrollDragZoomControl” to your project and use it as follows:
1 2 3 |
<controls:ScrollDragZoomControl> <!-- Your Content to present --> </controls:ScrollDragZoomControl> |
ABP – Alpha-Beta Pruning
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
private BiPredicate<Integer, Node> searchLimitingPredicate; private int depth; public AlphaBetaSearch(BiPredicate<Integer, Node> searchLimitingPredicate) { this.searchLimitingPredicate = searchLimitingPredicate; } public Pair<Node, Double> search(Node start, Function<Node, Double> evalFunction) { Node winner = start; double value = Double.NEGATIVE_INFINITY; double alpha = Double.NEGATIVE_INFINITY; double beta = Double.POSITIVE_INFINITY; for (Node n : start.adjacent()) { double temp = min(n, evalFunction, alpha, beta); if (temp > value) { value = temp; winner = n; } depth = 0; } return new Pair<Node, Double>(winner, value); } private double min(Node node, Function<Node, Double> evalFunction, double alpha, double beta) { if (node.isLeaf() || !searchLimitingPredicate.test(depth+1, node)) { return evalFunction.apply(node); } depth++; double value = Double.POSITIVE_INFINITY; for (Node n : node.adjacent()) { value = Math.min(value, max(n, evalFunction, alpha, beta)); if (value <= alpha) break; beta = Math.min(beta, value); } depth--; return value; } private double max(Node node, Function<Node, Double> evalFunction, double alpha, double beta) { if (node.isLeaf() || !searchLimitingPredicate.test(depth+1, node)) { return evalFunction.apply(node); } depth++; double value = Double.NEGATIVE_INFINITY; for (Node n : node.adjacent()) { value = Math.max(value, min(n, evalFunction, alpha, beta)); if (value >= beta) break; alpha = Math.max(alpha, value); } depth--; return value; } |