-
Notifications
You must be signed in to change notification settings - Fork 0
/
Player.cs
268 lines (231 loc) · 9.88 KB
/
Player.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
//------------------------------------------------------------------------------
// <copyright file="Player.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace ShapeGame
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using Microsoft.Kinect;
using ShapeGame.Utils;
public class Player
{
// Here is defined the size of the ellipse that represent each element (bones, Head, hands)
private const double BoneSize = 0.01;
private const double HeadSize = 0.075;
private const double HandSize = 0.03;
// Keeping track of all bone segments of interest as well as head, hands and feet
private readonly Dictionary<Bone, BoneData> segments = new Dictionary<Bone, BoneData>();
private readonly System.Windows.Media.Brush jointsBrush;
private readonly System.Windows.Media.Brush bonesBrush;
private readonly int id;
private static int colorId;
private Rect playerBounds; // ???
private System.Windows.Point playerCenter; //???
//??? I am expection that it render diferent persons (adults and childrens) ins same size, but it actually doesnt do it
private double playerScale;
public Player(int skeletonSlot)
{
this.id = skeletonSlot;
// Generate one of 7 colors for player
int[] mixR = { 1, 1, 1, 0, 1, 0, 0 };
int[] mixG = { 1, 1, 0, 1, 0, 1, 0 };
int[] mixB = { 1, 0, 1, 1, 0, 0, 1 };
byte[] jointCols = { 245, 200 };
byte[] boneCols = { 235, 160 };
int i = colorId;
colorId = (colorId + 1) % mixR.Count();
this.jointsBrush = new SolidColorBrush(System.Windows.Media.Color.FromRgb(jointCols[mixR[i]], jointCols[mixG[i]], jointCols[mixB[i]]));
this.bonesBrush = new SolidColorBrush(System.Windows.Media.Color.FromRgb(boneCols[mixR[i]], boneCols[mixG[i]], boneCols[mixB[i]]));
this.LastUpdated = DateTime.Now;
}
public bool IsAlive { get; set; }
public DateTime LastUpdated { get; set; }
public Dictionary<Bone, BoneData> Segments
{
get
{
return this.segments;
}
}
public int GetId()
{
return this.id;
}
// ???
public void SetBounds(Rect r)
{
this.playerBounds = r;
this.playerCenter.X = (this.playerBounds.Left + this.playerBounds.Right) / 2;
this.playerCenter.Y = (this.playerBounds.Top + this.playerBounds.Bottom) / 2;
// ??? whats player scale means?
this.playerScale = Math.Min(this.playerBounds.Width, this.playerBounds.Height / 2);
}
public void UpdateBonePosition(Microsoft.Kinect.JointCollection joints, JointType j1, JointType j2)
{
//??? what this do?
var seg = new Segment(
(joints[j1].Position.X * this.playerScale) + this.playerCenter.X,
this.playerCenter.Y - (joints[j1].Position.Y * this.playerScale),
(joints[j2].Position.X * this.playerScale) + this.playerCenter.X,
this.playerCenter.Y - (joints[j2].Position.Y * this.playerScale)) { Radius = Math.Max(3.0, this.playerBounds.Height * BoneSize) / 2 };
this.UpdateSegmentPosition(j1, j2, seg);
}
public void UpdateJointPosition(Microsoft.Kinect.JointCollection joints, JointType j)
{
//??? what this do?
var seg = new Segment(
(joints[j].Position.X * this.playerScale) + this.playerCenter.X,
this.playerCenter.Y - (joints[j].Position.Y * this.playerScale)) { Radius = this.playerBounds.Height * ((j == JointType.Head) ? HeadSize : HandSize) / 2 };
this.UpdateSegmentPosition(j, j, seg);
}
public void Draw(UIElementCollection children)
{
if (!this.IsAlive)
{
return;
}
// Draw all bones first, then circles (head and hands).
DateTime cur = DateTime.Now;
foreach (var segment in this.segments)
{
Segment seg = segment.Value.GetEstimatedSegment(cur);
if (!seg.IsCircle())
{
var line = new Line
{
StrokeThickness = seg.Radius * 2,
X1 = seg.X1,
Y1 = seg.Y1,
X2 = seg.X2,
Y2 = seg.Y2,
Stroke = this.bonesBrush,
StrokeEndLineCap = PenLineCap.Round,
StrokeStartLineCap = PenLineCap.Round
};
children.Add(line);
}
}
foreach (var segment in this.segments)
{
Segment seg = segment.Value.GetEstimatedSegment(cur);
if (seg.IsCircle())
{
var circle = new Ellipse { Width = seg.Radius * 2, Height = seg.Radius * 2 };
circle.SetValue(Canvas.LeftProperty, seg.X1 - seg.Radius);
circle.SetValue(Canvas.TopProperty, seg.Y1 - seg.Radius);
circle.Stroke = this.jointsBrush;
circle.StrokeThickness = 1;
circle.Fill = this.bonesBrush;
children.Add(circle);
}
}
// Remove unused players after 1/2 second.
if (DateTime.Now.Subtract(this.LastUpdated).TotalMilliseconds > 500)
{
this.IsAlive = false;
}
}
//??? Whats this do?
private void UpdateSegmentPosition(JointType j1, JointType j2, Segment seg)
{
var bone = new Bone(j1, j2);
if (this.segments.ContainsKey(bone))
{
BoneData data = this.segments[bone];
data.UpdateSegment(seg);
this.segments[bone] = data;
}
else
{
this.segments.Add(bone, new BoneData(seg));
}
}
}
#region "Copied from FallingShapes class, just for knowing"
// For hit testing, a dictionary of BoneData items, keyed off the endpoints
// of a segment (Bone) is used. The velocity of these endpoints is estimated
// and used during hit testing and updating velocity vectors after a hit.
public struct Bone
{
public JointType Joint1;
public JointType Joint2;
public Bone(JointType j1, JointType j2)
{
this.Joint1 = j1;
this.Joint2 = j2;
}
}
public struct BoneData
{
public Segment Segment;
public Segment LastSegment;
public double XVelocity;
public double YVelocity;
public double XVelocity2;
public double YVelocity2;
public DateTime TimeLastUpdated;
private const double Smoothing = 0.8;
public BoneData(Segment s)
{
this.Segment = this.LastSegment = s;
this.XVelocity = this.YVelocity = 0;
this.XVelocity2 = this.YVelocity2 = 0;
this.TimeLastUpdated = DateTime.Now;
}
// Update the segment's position and compute a smoothed velocity for the circle or the
// endpoints of the segment based on the time it took it to move from the last position
// to the current one. The velocity is in pixels per second.
public void UpdateSegment(Segment s)
{
this.LastSegment = this.Segment;
this.Segment = s;
DateTime cur = DateTime.Now;
double fMs = cur.Subtract(this.TimeLastUpdated).TotalMilliseconds;
if (fMs < 10.0)
{
fMs = 10.0;
}
double fps = 1000.0 / fMs;
this.TimeLastUpdated = cur;
if (this.Segment.IsCircle())
{
this.XVelocity = (this.XVelocity * Smoothing) + ((1.0 - Smoothing) * (this.Segment.X1 - this.LastSegment.X1) * fps);
this.YVelocity = (this.YVelocity * Smoothing) + ((1.0 - Smoothing) * (this.Segment.Y1 - this.LastSegment.Y1) * fps);
}
else
{
this.XVelocity = (this.XVelocity * Smoothing) + ((1.0 - Smoothing) * (this.Segment.X1 - this.LastSegment.X1) * fps);
this.YVelocity = (this.YVelocity * Smoothing) + ((1.0 - Smoothing) * (this.Segment.Y1 - this.LastSegment.Y1) * fps);
this.XVelocity2 = (this.XVelocity2 * Smoothing) + ((1.0 - Smoothing) * (this.Segment.X2 - this.LastSegment.X2) * fps);
this.YVelocity2 = (this.YVelocity2 * Smoothing) + ((1.0 - Smoothing) * (this.Segment.Y2 - this.LastSegment.Y2) * fps);
}
}
// Using the velocity calculated above, estimate where the segment is right now.
public Segment GetEstimatedSegment(DateTime cur)
{
Segment estimate = this.Segment;
double fMs = cur.Subtract(this.TimeLastUpdated).TotalMilliseconds;
estimate.X1 += fMs * this.XVelocity / 1000.0;
estimate.Y1 += fMs * this.YVelocity / 1000.0;
if (this.Segment.IsCircle())
{
estimate.X2 = estimate.X1;
estimate.Y2 = estimate.Y1;
}
else
{
estimate.X2 += fMs * this.XVelocity2 / 1000.0;
estimate.Y2 += fMs * this.YVelocity2 / 1000.0;
}
return estimate;
}
}
#endregion
}