Imported existing sources
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
public class AnimationClip
|
||||||
|
{
|
||||||
|
public class Bone
|
||||||
|
{
|
||||||
|
public class Keyframe
|
||||||
|
{
|
||||||
|
public double Time;
|
||||||
|
public Quaternion Rotation;
|
||||||
|
public Vector3 Translation;
|
||||||
|
|
||||||
|
public Matrix Transform
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Matrix.CreateFromQuaternion(Rotation) * Matrix.CreateTranslation(Translation);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Matrix transform = value;
|
||||||
|
transform.Right = Vector3.Normalize(transform.Right);
|
||||||
|
transform.Up = Vector3.Normalize(transform.Up);
|
||||||
|
transform.Backward = Vector3.Normalize(transform.Backward);
|
||||||
|
Rotation = Quaternion.CreateFromRotationMatrix(transform);
|
||||||
|
Translation = transform.Translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string name = "";
|
||||||
|
private List<Keyframe> keyframes = new List<Keyframe>();
|
||||||
|
public string Name { get { return name; } set { name = value; } }
|
||||||
|
public List<Keyframe> Keyframes { get { return keyframes; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Bone> bones = new List<Bone>();
|
||||||
|
public string Name;
|
||||||
|
public double Duration;
|
||||||
|
public List<Bone> Bones { get { return bones; } }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Content;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
public class AnimationClipReader : ContentTypeReader<AnimationClip>
|
||||||
|
{
|
||||||
|
protected override AnimationClip Read(ContentReader input, AnimationClip existingInstance)
|
||||||
|
{
|
||||||
|
var clip = new AnimationClip();
|
||||||
|
clip.Name = input.ReadString();
|
||||||
|
clip.Duration = input.ReadDouble();
|
||||||
|
|
||||||
|
int boneCnt = input.ReadInt32();
|
||||||
|
for (int i = 0; i < boneCnt; i++)
|
||||||
|
{
|
||||||
|
var bone = new AnimationClip.Bone();
|
||||||
|
clip.Bones.Add(bone);
|
||||||
|
|
||||||
|
bone.Name = input.ReadString();
|
||||||
|
|
||||||
|
int keyframeCnt = input.ReadInt32();
|
||||||
|
for (int j = 0; j < keyframeCnt; j++)
|
||||||
|
{
|
||||||
|
var keyframe = new AnimationClip.Bone.Keyframe();
|
||||||
|
keyframe.Time = input.ReadDouble();
|
||||||
|
keyframe.Rotation = input.ReadQuaternion();
|
||||||
|
keyframe.Translation = input.ReadVector3();
|
||||||
|
|
||||||
|
bone.Keyframes.Add(keyframe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
[ContentTypeWriter]
|
||||||
|
public class AnimationClipWriter : ContentTypeWriter<AnimationClip>
|
||||||
|
{
|
||||||
|
protected override void Write(ContentWriter output, AnimationClip clip)
|
||||||
|
{
|
||||||
|
output.Write(clip.Name);
|
||||||
|
output.Write(clip.Duration);
|
||||||
|
output.Write(clip.Bones.Count);
|
||||||
|
|
||||||
|
foreach (var bone in clip.Bones)
|
||||||
|
{
|
||||||
|
output.Write(bone.Name);
|
||||||
|
output.Write(bone.Keyframes.Count);
|
||||||
|
|
||||||
|
foreach (var keyframe in bone.Keyframes)
|
||||||
|
{
|
||||||
|
output.Write(keyframe.Time);
|
||||||
|
output.Write(keyframe.Rotation);
|
||||||
|
output.Write(keyframe.Translation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetRuntimeReader(TargetPlatform targetPlatform)
|
||||||
|
{
|
||||||
|
return typeof(AnimationClipReader).AssemblyQualifiedName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,315 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
[ContentProcessor(DisplayName = "Animation Processor")]
|
||||||
|
public class AnimationProcessor : ModelProcessor
|
||||||
|
{
|
||||||
|
private ModelContent model;
|
||||||
|
private ModelExtra modelExtra = new ModelExtra();
|
||||||
|
private Dictionary<MaterialContent, SkinnedMaterialContent> toSkinnedMaterial = new Dictionary<MaterialContent, SkinnedMaterialContent>();
|
||||||
|
private Dictionary<string, int> bones = new Dictionary<string, int>();
|
||||||
|
private Matrix[] boneTransforms;
|
||||||
|
private Dictionary<string, AnimationClip> clips = new Dictionary<string, AnimationClip>();
|
||||||
|
|
||||||
|
public override ModelContent Process(NodeContent input, ContentProcessorContext context)
|
||||||
|
{
|
||||||
|
var skeleton = ProcessSkeleton(input);
|
||||||
|
SwapSkinnedMaterial(input);
|
||||||
|
model = base.Process(input, context);
|
||||||
|
ProcessAnimations(model, input, context);
|
||||||
|
model.Tag = modelExtra;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoneContent ProcessSkeleton(NodeContent input)
|
||||||
|
{
|
||||||
|
var skeleton = MeshHelper.FindSkeleton(input);
|
||||||
|
|
||||||
|
if (skeleton == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
FlattenTransforms(input, skeleton);
|
||||||
|
TrimSkeleton(skeleton);
|
||||||
|
|
||||||
|
var nodes = FlattenHeirarchy(input);
|
||||||
|
var bones = MeshHelper.FlattenSkeleton(skeleton);
|
||||||
|
|
||||||
|
var nodeToIndex = new Dictionary<NodeContent, int>();
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
nodeToIndex[nodes[i]] = i;
|
||||||
|
|
||||||
|
foreach (var bone in bones)
|
||||||
|
modelExtra.Skeleton.Add(nodeToIndex[bone]);
|
||||||
|
|
||||||
|
return skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<NodeContent> FlattenHeirarchy(NodeContent item)
|
||||||
|
{
|
||||||
|
var nodes = new List<NodeContent>();
|
||||||
|
nodes.Add(item);
|
||||||
|
|
||||||
|
foreach (var child in item.Children)
|
||||||
|
FlattenHeirarchy(nodes, child);
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FlattenHeirarchy(List<NodeContent> nodes, NodeContent item)
|
||||||
|
{
|
||||||
|
nodes.Add(item);
|
||||||
|
foreach (var child in item.Children)
|
||||||
|
FlattenHeirarchy(nodes, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlattenTransforms(NodeContent node, BoneContent skeleton)
|
||||||
|
{
|
||||||
|
foreach (var child in node.Children)
|
||||||
|
{
|
||||||
|
if (child == skeleton)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(IsSkinned(child))
|
||||||
|
FlattenAllTransforms(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlattenAllTransforms(NodeContent node)
|
||||||
|
{
|
||||||
|
MeshHelper.TransformScene(node, node.Transform);
|
||||||
|
|
||||||
|
node.Transform = Matrix.Identity;
|
||||||
|
|
||||||
|
foreach (var child in node.Children)
|
||||||
|
FlattenAllTransforms(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrimSkeleton(NodeContent skeleton)
|
||||||
|
{
|
||||||
|
var todelete = new List<NodeContent>();
|
||||||
|
|
||||||
|
foreach (var child in skeleton.Children)
|
||||||
|
if (child.Name.EndsWith("Nub") || child.Name.EndsWith("Footsteps"))
|
||||||
|
todelete.Add(child);
|
||||||
|
else
|
||||||
|
TrimSkeleton(child);
|
||||||
|
|
||||||
|
foreach (var child in todelete)
|
||||||
|
skeleton.Children.Remove(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSkinned(NodeContent node)
|
||||||
|
{
|
||||||
|
var mesh = node as MeshContent;
|
||||||
|
if (mesh != null)
|
||||||
|
foreach (var geometry in mesh.Geometry)
|
||||||
|
foreach (var vchannel in geometry.Vertices.Channels)
|
||||||
|
if (vchannel is VertexChannel<BoneWeightCollection>)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapSkinnedMaterial(NodeContent node)
|
||||||
|
{
|
||||||
|
var mesh = node as MeshContent;
|
||||||
|
if (mesh != null)
|
||||||
|
{
|
||||||
|
foreach (var geometry in mesh.Geometry)
|
||||||
|
{
|
||||||
|
bool swap = false;
|
||||||
|
foreach (var vchannel in geometry.Vertices.Channels)
|
||||||
|
{
|
||||||
|
if (vchannel is VertexChannel<BoneWeightCollection>)
|
||||||
|
{
|
||||||
|
swap = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swap)
|
||||||
|
{
|
||||||
|
if (toSkinnedMaterial.ContainsKey(geometry.Material))
|
||||||
|
geometry.Material = toSkinnedMaterial[geometry.Material];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var smaterial = new SkinnedMaterialContent();
|
||||||
|
var bmaterial = geometry.Material as BasicMaterialContent;
|
||||||
|
|
||||||
|
smaterial.Alpha = bmaterial.Alpha;
|
||||||
|
smaterial.DiffuseColor = bmaterial.DiffuseColor;
|
||||||
|
smaterial.EmissiveColor = bmaterial.EmissiveColor;
|
||||||
|
smaterial.SpecularColor = bmaterial.SpecularColor;
|
||||||
|
smaterial.SpecularPower = bmaterial.SpecularPower;
|
||||||
|
smaterial.Texture = bmaterial.Texture;
|
||||||
|
smaterial.WeightsPerVertex = 4;
|
||||||
|
|
||||||
|
toSkinnedMaterial[geometry.Material] = smaterial;
|
||||||
|
geometry.Material = smaterial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in node.Children)
|
||||||
|
SwapSkinnedMaterial(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessAnimations(ModelContent model, NodeContent input, ContentProcessorContext context)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < model.Bones.Count; i++)
|
||||||
|
bones[model.Bones[i].Name] = i;
|
||||||
|
|
||||||
|
boneTransforms = new Matrix[model.Bones.Count];
|
||||||
|
|
||||||
|
ProcessAnimationsRecursive(input);
|
||||||
|
|
||||||
|
if (modelExtra.Clips.Count == 0)
|
||||||
|
{
|
||||||
|
var clip = new AnimationClip();
|
||||||
|
modelExtra.Clips.Add(clip);
|
||||||
|
|
||||||
|
var clipName = "Take 001";
|
||||||
|
|
||||||
|
clips[clipName] = clip;
|
||||||
|
|
||||||
|
clip.Name = clipName;
|
||||||
|
foreach (var bone in model.Bones)
|
||||||
|
{
|
||||||
|
var clipBone = new AnimationClip.Bone();
|
||||||
|
clipBone.Name = bone.Name;
|
||||||
|
|
||||||
|
clip.Bones.Add(clipBone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var clip in modelExtra.Clips)
|
||||||
|
{
|
||||||
|
for (int b = 0; b < bones.Count; b++)
|
||||||
|
{
|
||||||
|
var keyframes = clip.Bones[b].Keyframes;
|
||||||
|
if (keyframes.Count == 0 || keyframes[0].Time > 0)
|
||||||
|
{
|
||||||
|
var keyframe = new AnimationClip.Bone.Keyframe();
|
||||||
|
keyframe.Time = 0;
|
||||||
|
keyframe.Transform = boneTransforms[b];
|
||||||
|
keyframes.Insert(0, keyframe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessAnimationsRecursive(NodeContent input)
|
||||||
|
{
|
||||||
|
int inputBoneIndex;
|
||||||
|
if (bones.TryGetValue(input.Name, out inputBoneIndex))
|
||||||
|
boneTransforms[inputBoneIndex] = input.Transform;
|
||||||
|
|
||||||
|
foreach (var animation in input.Animations)
|
||||||
|
{
|
||||||
|
AnimationClip clip;
|
||||||
|
string clipName = animation.Key;
|
||||||
|
|
||||||
|
if (!clips.TryGetValue(clipName, out clip))
|
||||||
|
{
|
||||||
|
clip = new AnimationClip();
|
||||||
|
modelExtra.Clips.Add(clip);
|
||||||
|
|
||||||
|
clips[clipName] = clip;
|
||||||
|
|
||||||
|
clip.Name = clipName;
|
||||||
|
foreach (var bone in model.Bones)
|
||||||
|
{
|
||||||
|
var clipBone = new AnimationClip.Bone();
|
||||||
|
clipBone.Name = bone.Name;
|
||||||
|
|
||||||
|
clip.Bones.Add(clipBone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animation.Value.Duration.TotalSeconds > clip.Duration)
|
||||||
|
clip.Duration = animation.Value.Duration.TotalSeconds;
|
||||||
|
|
||||||
|
foreach (var channel in animation.Value.Channels)
|
||||||
|
{
|
||||||
|
int boneIndex;
|
||||||
|
if (!bones.TryGetValue(channel.Key, out boneIndex))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (UselessAnimationTest(boneIndex))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var keyframes = new LinkedList<AnimationClip.Bone.Keyframe>();
|
||||||
|
foreach (var keyframe in channel.Value)
|
||||||
|
{
|
||||||
|
var transform = keyframe.Transform;
|
||||||
|
|
||||||
|
var newKeyframe = new AnimationClip.Bone.Keyframe();
|
||||||
|
newKeyframe.Time = keyframe.Time.TotalSeconds;
|
||||||
|
newKeyframe.Transform = transform;
|
||||||
|
|
||||||
|
keyframes.AddLast(newKeyframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearKeyframeReduction(keyframes);
|
||||||
|
foreach (var keyframe in keyframes)
|
||||||
|
clip.Bones[boneIndex].Keyframes.Add(keyframe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in input.Children)
|
||||||
|
ProcessAnimationsRecursive(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float TinyLength = 1e-8f;
|
||||||
|
private const float TinyCosAngle = 0.9999999f;
|
||||||
|
|
||||||
|
private void LinearKeyframeReduction(LinkedList<AnimationClip.Bone.Keyframe> keyframes)
|
||||||
|
{
|
||||||
|
if (keyframes.Count < 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var node = keyframes.First.Next; ; )
|
||||||
|
{
|
||||||
|
var next = node.Next;
|
||||||
|
if (next == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Determine nodes before and after the current node.
|
||||||
|
var a = node.Previous.Value;
|
||||||
|
var b = node.Value;
|
||||||
|
var c = next.Value;
|
||||||
|
|
||||||
|
var t = (float)((node.Value.Time - node.Previous.Value.Time) / (next.Value.Time - node.Previous.Value.Time));
|
||||||
|
|
||||||
|
var translation = Vector3.Lerp(a.Translation, c.Translation, t);
|
||||||
|
var rotation = Quaternion.Slerp(a.Rotation, c.Rotation, t);
|
||||||
|
|
||||||
|
if ((translation - b.Translation).LengthSquared() < TinyLength && Quaternion.Dot(rotation, b.Rotation) > TinyCosAngle)
|
||||||
|
keyframes.Remove(node);
|
||||||
|
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UselessAnimationTest(int boneId)
|
||||||
|
{
|
||||||
|
foreach (var mesh in model.Meshes)
|
||||||
|
if (mesh.ParentBone.Index == boneId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (int b in modelExtra.Skeleton)
|
||||||
|
if (boneId == b)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectGuid>{9975ED45-7A21-4F8A-9EC3-12F5845F681F}</ProjectGuid>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>FluckyGame.Client.Pipeline.Animation</RootNamespace>
|
||||||
|
<AssemblyName>FluckyGame.Client.Pipeline.Animation</AssemblyName>
|
||||||
|
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
|
||||||
|
<XnaPlatform>Windows</XnaPlatform>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkProfile>
|
||||||
|
</TargetFrameworkProfile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\x86\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\x86\Release</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
||||||
|
<SpecificVersion>True</SpecificVersion>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
||||||
|
<SpecificVersion>True</SpecificVersion>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
||||||
|
<SpecificVersion>true</SpecificVersion>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.Linq">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="AnimationClip.cs" />
|
||||||
|
<Compile Include="AnimationClipReader.cs" />
|
||||||
|
<Compile Include="AnimationClipWriter.cs" />
|
||||||
|
<Compile Include="AnimationProcessor.cs" />
|
||||||
|
<Compile Include="ModelExtra.cs" />
|
||||||
|
<Compile Include="ModelExtraReader.cs" />
|
||||||
|
<Compile Include="ModelExtraWriter.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
public class ModelExtra
|
||||||
|
{
|
||||||
|
private List<int> skeleton = new List<int>();
|
||||||
|
private List<AnimationClip> clips = new List<AnimationClip>();
|
||||||
|
|
||||||
|
public List<int> Skeleton { get { return skeleton; } set { skeleton = value; } }
|
||||||
|
public List<AnimationClip> Clips { get { return clips; } set { clips = value; } }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Content;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
public class ModelExtraReader : ContentTypeReader<ModelExtra>
|
||||||
|
{
|
||||||
|
protected override ModelExtra Read(ContentReader input, ModelExtra existingInstance)
|
||||||
|
{
|
||||||
|
var extra = new ModelExtra();
|
||||||
|
extra.Skeleton = input.ReadObject<List<int>>();
|
||||||
|
extra.Clips = input.ReadObject<List<AnimationClip>>();
|
||||||
|
return extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||||
|
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Pipeline.Animation
|
||||||
|
{
|
||||||
|
[ContentTypeWriter]
|
||||||
|
public class ModelExtraWriter : ContentTypeWriter<ModelExtra>
|
||||||
|
{
|
||||||
|
protected override void Write(ContentWriter output, ModelExtra extra)
|
||||||
|
{
|
||||||
|
output.WriteObject(extra.Skeleton);
|
||||||
|
output.WriteObject(extra.Clips);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetRuntimeReader(TargetPlatform targetPlatform)
|
||||||
|
{
|
||||||
|
return typeof(ModelExtraReader).AssemblyQualifiedName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("FluckyGame.Client.Pipeline.Animation")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("FluckyGame.Client.Pipeline.Animation")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("9975ed45-7a21-4f8a-9ec3-12f5845f681f")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
68
src/FluckyGame.Client/FluckyGame.Client/Bone.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client
|
||||||
|
{
|
||||||
|
public class Bone
|
||||||
|
{
|
||||||
|
private Bone parent = null;
|
||||||
|
private List<Bone> children = new List<Bone>();
|
||||||
|
private Matrix bindTransform = Matrix.Identity;
|
||||||
|
private Vector3 bindScale = Vector3.One;
|
||||||
|
private Vector3 translation = Vector3.Zero;
|
||||||
|
private Quaternion rotation = Quaternion.Identity;
|
||||||
|
private Vector3 scale = Vector3.One;
|
||||||
|
|
||||||
|
public string Name = "";
|
||||||
|
public Matrix BindTransform { get { return bindTransform; } }
|
||||||
|
public Matrix SkinTransform { get; set; }
|
||||||
|
public Quaternion Rotation { get { return rotation; } set { rotation = value; } }
|
||||||
|
public Vector3 Translation { get { return translation; } set { translation = value; } }
|
||||||
|
public Vector3 Scale { get { return scale; } set { scale = value; } }
|
||||||
|
public Bone Parent { get { return parent; } }
|
||||||
|
public List<Bone> Children { get { return children; } }
|
||||||
|
public Matrix AbsoluteTransform = Matrix.Identity;
|
||||||
|
|
||||||
|
public Bone(string name, Matrix bindTransform, Bone parent)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
this.parent = parent;
|
||||||
|
if (parent != null)
|
||||||
|
parent.children.Add(this);
|
||||||
|
|
||||||
|
this.bindScale = new Vector3(bindTransform.Right.Length(),
|
||||||
|
bindTransform.Up.Length(), bindTransform.Backward.Length());
|
||||||
|
|
||||||
|
bindTransform.Right = bindTransform.Right / bindScale.X;
|
||||||
|
bindTransform.Up = bindTransform.Up / bindScale.Y;
|
||||||
|
bindTransform.Backward = bindTransform.Backward / bindScale.Y;
|
||||||
|
this.bindTransform = bindTransform;
|
||||||
|
|
||||||
|
ComputeAbsoluteTransform();
|
||||||
|
SkinTransform = Matrix.Invert(AbsoluteTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ComputeAbsoluteTransform()
|
||||||
|
{
|
||||||
|
var transform =
|
||||||
|
Matrix.CreateScale(Scale * bindScale) *
|
||||||
|
Matrix.CreateFromQuaternion(Rotation) *
|
||||||
|
Matrix.CreateTranslation(Translation) *
|
||||||
|
BindTransform;
|
||||||
|
|
||||||
|
if (Parent != null)
|
||||||
|
AbsoluteTransform = transform * Parent.AbsoluteTransform;
|
||||||
|
else
|
||||||
|
AbsoluteTransform = transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCompleteTransform(Matrix m)
|
||||||
|
{
|
||||||
|
var setTo = m * Matrix.Invert(BindTransform);
|
||||||
|
|
||||||
|
Translation = setTo.Translation;
|
||||||
|
Rotation = Quaternion.CreateFromRotationMatrix(setTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Entities
|
||||||
|
{
|
||||||
|
class BouncingEntity : ModelEntity
|
||||||
|
{
|
||||||
|
float ySpeed;
|
||||||
|
|
||||||
|
const float randomMin = 1;
|
||||||
|
const float randomMax = 5;
|
||||||
|
|
||||||
|
public BouncingEntity(Model model) :
|
||||||
|
base(model)
|
||||||
|
{
|
||||||
|
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BouncingEntity(Model model, Vector3 position) :
|
||||||
|
base(model, position)
|
||||||
|
{
|
||||||
|
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BouncingEntity(Model model, Vector3 position, Vector3 rotation) :
|
||||||
|
base(model, position, rotation)
|
||||||
|
{
|
||||||
|
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BouncingEntity(Model model, Vector3 position, Vector3 rotation, Vector3 scalation) :
|
||||||
|
base(model, position, rotation, scalation)
|
||||||
|
{
|
||||||
|
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(GameTime gameTime, KeyboardState keyboardState, MouseState mouseState)
|
||||||
|
{
|
||||||
|
base.Update(gameTime, keyboardState, mouseState);
|
||||||
|
|
||||||
|
if (Position.Y > 0)
|
||||||
|
ySpeed -= 0.1f / 17 * gameTime.ElapsedGameTime.Milliseconds;
|
||||||
|
else
|
||||||
|
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
|
||||||
|
Position.Y += ySpeed / 17 * gameTime.ElapsedGameTime.Milliseconds;
|
||||||
|
|
||||||
|
UpdateWorld();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/FluckyGame.Client/FluckyGame.Client/Entities/Entity.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client
|
||||||
|
{
|
||||||
|
public class Entity
|
||||||
|
{
|
||||||
|
public virtual void Update(GameTime gameTime, KeyboardState keyboardState, MouseState mouseState)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public virtual void Draw(GameTime gameTime)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
288
src/FluckyGame.Client/FluckyGame.Client/Entities/ModelEntity.cs
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using FluckyGame.Client.Pipeline.Animation;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Entities
|
||||||
|
{
|
||||||
|
public class ModelEntity : Entity
|
||||||
|
{
|
||||||
|
public Vector3 Position;
|
||||||
|
public Vector3 Rotation;
|
||||||
|
public Vector3 Scalation;
|
||||||
|
|
||||||
|
Model model;
|
||||||
|
public Model Model { get { return model; } }
|
||||||
|
|
||||||
|
AnimationClip animationClip;
|
||||||
|
public AnimationClip AnimationClip
|
||||||
|
{
|
||||||
|
get { return animationClip; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
if (animationClip == null)
|
||||||
|
throw new Exception("No clip playing!");
|
||||||
|
|
||||||
|
animationClip = value;
|
||||||
|
boneInfos = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (animationClip != null)
|
||||||
|
throw new Exception("Another clip playing!");
|
||||||
|
|
||||||
|
animationClip = value;
|
||||||
|
animationPlaying = false;
|
||||||
|
animationLooping = false;
|
||||||
|
animationDuration = (float)animationClip.Duration;
|
||||||
|
animationSpeed = 1;
|
||||||
|
boneInfos = new BoneInfo[animationClip.Bones.Count];
|
||||||
|
for (int i = 0; i < boneInfos.Length; i++)
|
||||||
|
boneInfos[i] = new BoneInfo(model, animationClip.Bones[i]);
|
||||||
|
animationPosition = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool animationPlaying;
|
||||||
|
public bool AnimationPlaying
|
||||||
|
{
|
||||||
|
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationPlaying; }
|
||||||
|
set { if (animationClip == null) throw new Exception("No clip playing!"); else animationPlaying = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool animationLooping;
|
||||||
|
public bool AnimationLooping
|
||||||
|
{
|
||||||
|
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationLooping; }
|
||||||
|
set { if (animationClip == null) throw new Exception("No clip playing!"); else animationLooping = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
float animationDuration;
|
||||||
|
public float AnimationDuration
|
||||||
|
{
|
||||||
|
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationDuration; }
|
||||||
|
}
|
||||||
|
|
||||||
|
float animationSpeed;
|
||||||
|
public float AnimationSpeed
|
||||||
|
{
|
||||||
|
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationSpeed; }
|
||||||
|
set { if (animationClip == null) throw new Exception("No clip playing!"); else animationSpeed = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
float animationPosition;
|
||||||
|
public float AnimationPosition
|
||||||
|
{
|
||||||
|
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationPosition; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (animationClip == null)
|
||||||
|
throw new Exception("No clip playing!");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
animationPosition = value;
|
||||||
|
|
||||||
|
while (animationPosition < 0)
|
||||||
|
animationPosition += animationDuration;
|
||||||
|
|
||||||
|
while (animationPosition > animationDuration)
|
||||||
|
animationPosition -= animationDuration;
|
||||||
|
|
||||||
|
foreach (var bone in boneInfos)
|
||||||
|
bone.SetPosition(animationPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoneInfo[] boneInfos;
|
||||||
|
|
||||||
|
Matrix world;
|
||||||
|
|
||||||
|
public ModelEntity(Model model)
|
||||||
|
{
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
Position = Vector3.Zero;
|
||||||
|
Rotation = Vector3.Zero;
|
||||||
|
Scalation = new Vector3(1, 1, 1);
|
||||||
|
|
||||||
|
UpdateWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelEntity(Model model, Vector3 position)
|
||||||
|
{
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
this.Position = position;
|
||||||
|
Rotation = Vector3.Zero;
|
||||||
|
Scalation = new Vector3(1, 1, 1);
|
||||||
|
|
||||||
|
UpdateWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelEntity(Model model, Vector3 position, Vector3 rotation)
|
||||||
|
{
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
this.Position = position;
|
||||||
|
this.Rotation = rotation;
|
||||||
|
Scalation = new Vector3(1, 1, 1);
|
||||||
|
|
||||||
|
UpdateWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelEntity(Model model, Vector3 position, Vector3 rotation, Vector3 scalation)
|
||||||
|
{
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
this.Position = position;
|
||||||
|
this.Rotation = rotation;
|
||||||
|
this.Scalation = scalation;
|
||||||
|
|
||||||
|
UpdateWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateWorld()
|
||||||
|
{
|
||||||
|
world = Matrix.CreateScale(Scalation) * Matrix.CreateFromYawPitchRoll(Rotation.X, Rotation.Y, Rotation.Z) * Matrix.CreateTranslation(Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(GameTime gameTime)
|
||||||
|
{
|
||||||
|
if (animationClip == null)
|
||||||
|
{
|
||||||
|
foreach (var mesh in model.Meshes)
|
||||||
|
{
|
||||||
|
foreach (var effect in mesh.Effects)
|
||||||
|
if (effect is IEffectMatrices)
|
||||||
|
(effect as IEffectMatrices).World = world;
|
||||||
|
|
||||||
|
mesh.Draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (animationPlaying)
|
||||||
|
{
|
||||||
|
AnimationPosition += (float)gameTime.ElapsedGameTime.TotalSeconds * animationSpeed;
|
||||||
|
if (AnimationLooping && AnimationPosition >= AnimationDuration)
|
||||||
|
AnimationPosition -= AnimationDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modelExtra = Game1.currentInstance.modelExtras[model];
|
||||||
|
var bones = Game1.currentInstance.modelBones[model];
|
||||||
|
|
||||||
|
var boneTransforms = new Matrix[bones.Count];
|
||||||
|
for (int i = 0; i < bones.Count; i++)
|
||||||
|
{
|
||||||
|
var bone = bones[i];
|
||||||
|
bone.ComputeAbsoluteTransform();
|
||||||
|
boneTransforms[i] = bone.AbsoluteTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
var skeleton = new Matrix[modelExtra.Skeleton.Count];
|
||||||
|
for (int s = 0; s < modelExtra.Skeleton.Count; s++)
|
||||||
|
{
|
||||||
|
var bone = bones[modelExtra.Skeleton[s]];
|
||||||
|
skeleton[s] = bone.SkinTransform * bone.AbsoluteTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var modelMesh in model.Meshes)
|
||||||
|
{
|
||||||
|
foreach (var effect in modelMesh.Effects)
|
||||||
|
{
|
||||||
|
if (effect is IEffectMatrices)
|
||||||
|
(effect as IEffectMatrices).World = boneTransforms[modelMesh.ParentBone.Index] * world;
|
||||||
|
|
||||||
|
if (effect is SkinnedEffect)
|
||||||
|
(effect as SkinnedEffect).SetBoneTransforms(skeleton);
|
||||||
|
|
||||||
|
modelMesh.Draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BoneInfo
|
||||||
|
{
|
||||||
|
private int currentKeyframe = 0;
|
||||||
|
private Bone assignedBone = null;
|
||||||
|
public bool valid = false;
|
||||||
|
private Quaternion rotation;
|
||||||
|
public Vector3 translation;
|
||||||
|
public AnimationClip.Bone.Keyframe Keyframe1;
|
||||||
|
public AnimationClip.Bone.Keyframe Keyframe2;
|
||||||
|
|
||||||
|
public AnimationClip.Bone ClipBone { get; set; }
|
||||||
|
public Bone ModelBone { get { return assignedBone; } }
|
||||||
|
|
||||||
|
public BoneInfo(Model model, AnimationClip.Bone bone)
|
||||||
|
{
|
||||||
|
this.ClipBone = bone;
|
||||||
|
SetKeyframes();
|
||||||
|
SetPosition(0);
|
||||||
|
assignedBone = Game1.currentInstance.modelBones[model].FirstOrDefault(o => o.Name == ClipBone.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPosition(float position)
|
||||||
|
{
|
||||||
|
var keyframes = ClipBone.Keyframes;
|
||||||
|
if (keyframes.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (position < Keyframe1.Time && currentKeyframe > 0)
|
||||||
|
{
|
||||||
|
currentKeyframe--;
|
||||||
|
SetKeyframes();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (position >= Keyframe2.Time && currentKeyframe < ClipBone.Keyframes.Count - 2)
|
||||||
|
{
|
||||||
|
currentKeyframe++;
|
||||||
|
SetKeyframes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Keyframe1 == Keyframe2)
|
||||||
|
{
|
||||||
|
rotation = Keyframe1.Rotation;
|
||||||
|
translation = Keyframe1.Translation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var t = (float)((position - Keyframe1.Time) / (Keyframe2.Time - Keyframe1.Time));
|
||||||
|
rotation = Quaternion.Slerp(Keyframe1.Rotation, Keyframe2.Rotation, t);
|
||||||
|
translation = Vector3.Lerp(Keyframe1.Translation, Keyframe2.Translation, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
valid = true;
|
||||||
|
if (assignedBone != null)
|
||||||
|
{
|
||||||
|
var m = Matrix.CreateFromQuaternion(rotation);
|
||||||
|
m.Translation = translation;
|
||||||
|
assignedBone.SetCompleteTransform(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetKeyframes()
|
||||||
|
{
|
||||||
|
if (ClipBone.Keyframes.Count > 0)
|
||||||
|
{
|
||||||
|
Keyframe1 = ClipBone.Keyframes[currentKeyframe];
|
||||||
|
if (currentKeyframe == ClipBone.Keyframes.Count - 1)
|
||||||
|
Keyframe2 = Keyframe1;
|
||||||
|
else
|
||||||
|
Keyframe2 = ClipBone.Keyframes[currentKeyframe + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Keyframe1 = null;
|
||||||
|
Keyframe2 = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
src/FluckyGame.Client/FluckyGame.Client/Entities/PlayerEntity.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using FluckyGame.Library;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Entities
|
||||||
|
{
|
||||||
|
public class PlayerEntity : ModelEntity
|
||||||
|
{
|
||||||
|
bool lastDragging;
|
||||||
|
|
||||||
|
float cameraYaw;
|
||||||
|
float CameraYaw { get { return cameraYaw; } }
|
||||||
|
|
||||||
|
float cameraPitch;
|
||||||
|
float CameraPitch { get { return cameraPitch; } }
|
||||||
|
|
||||||
|
float cameraDistance;
|
||||||
|
float CameraDistance { get { return cameraDistance; } }
|
||||||
|
|
||||||
|
public PlayerEntity() :
|
||||||
|
base(Game1.currentInstance.models["dude"])
|
||||||
|
{
|
||||||
|
AnimationClip = Game1.currentInstance.modelExtras[Model].Clips[0];
|
||||||
|
AnimationLooping = true;
|
||||||
|
|
||||||
|
cameraDistance = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(GameTime gameTime, KeyboardState keyboardState, MouseState mouseState)
|
||||||
|
{
|
||||||
|
base.Update(gameTime, keyboardState, mouseState);
|
||||||
|
|
||||||
|
var shift = keyboardState.IsKeyDown(Keys.LeftShift);
|
||||||
|
|
||||||
|
if (keyboardState.IsKeyDown(Keys.W))
|
||||||
|
Position += Vector3.Transform(new Vector3(0, 0, shift ? -3 :-1), Matrix.CreateRotationY(Rotation.X));
|
||||||
|
|
||||||
|
if (keyboardState.IsKeyDown(Keys.S))
|
||||||
|
Position += Vector3.Transform(new Vector3(0, 0, shift ? 3 : 1), Matrix.CreateRotationY(Rotation.X));
|
||||||
|
|
||||||
|
if (keyboardState.IsKeyDown(Keys.A))
|
||||||
|
Rotation.X += 0.05f;
|
||||||
|
|
||||||
|
if (keyboardState.IsKeyDown(Keys.D))
|
||||||
|
Rotation.X -= 0.05f;
|
||||||
|
|
||||||
|
Rotation.X = MathHelper.WrapAngle(Rotation.X);
|
||||||
|
|
||||||
|
if (Game1.currentInstance.IsActive)
|
||||||
|
{
|
||||||
|
bool currentlyDragging = mouseState.LeftButton == ButtonState.Pressed;
|
||||||
|
|
||||||
|
if (currentlyDragging)
|
||||||
|
{
|
||||||
|
var centerX = Game1.currentInstance.graphicsDeviceManager.PreferredBackBufferWidth / 2;
|
||||||
|
var centerY = Game1.currentInstance.graphicsDeviceManager.PreferredBackBufferHeight / 2;
|
||||||
|
|
||||||
|
if (lastDragging)
|
||||||
|
{
|
||||||
|
cameraYaw -= (mouseState.X - centerX) / 500.0f;
|
||||||
|
cameraPitch -= (mouseState.Y - centerY) / 500.0f;
|
||||||
|
|
||||||
|
cameraYaw = MathHelper.WrapAngle(cameraYaw);
|
||||||
|
cameraPitch = MathHelper.Clamp(cameraPitch, -MathHelper.PiOver2, MathHelper.PiOver2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mouse.SetPosition(centerX, centerY);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastDragging = currentlyDragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboardState.IsKeyDown(Keys.W) ||
|
||||||
|
keyboardState.IsKeyDown(Keys.S) ||
|
||||||
|
keyboardState.IsKeyDown(Keys.A) ||
|
||||||
|
keyboardState.IsKeyDown(Keys.D))
|
||||||
|
{
|
||||||
|
AnimationPlaying = true;
|
||||||
|
AnimationSpeed = keyboardState.IsKeyDown(Keys.S) ? (shift ? -3 : -1) : (shift ? 3 : 1);
|
||||||
|
if (Game1.currentInstance.IsActive && mouseState.LeftButton == ButtonState.Released)
|
||||||
|
{
|
||||||
|
cameraYaw = MathHelper.SmoothStep(cameraYaw, new List<float>() { Rotation.X - MathHelper.TwoPi, Rotation.X, Rotation.X + MathHelper.TwoPi }.OrderBy(o => Math.Abs(o - cameraYaw)).First(), 0.1f);
|
||||||
|
cameraPitch = MathHelper.SmoothStep(cameraPitch, Rotation.Y + (MathHelper.PiOver4 / 4), 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Game1.currentInstance.SendPacket(new Packet() {
|
||||||
|
{ "type", "PLAYER" },
|
||||||
|
{ "position", Position },
|
||||||
|
{ "rotation", Rotation }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AnimationPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateWorld();
|
||||||
|
|
||||||
|
var test = new Vector3(0, 50, 0);
|
||||||
|
|
||||||
|
var view = Matrix.CreateLookAt(test + Position + Vector3.Transform(new Vector3(0, cameraDistance, 0), Matrix.CreateRotationX(cameraPitch - MathHelper.PiOver2) * Matrix.CreateRotationY(cameraYaw - MathHelper.Pi)), test + Position, Vector3.Up);
|
||||||
|
foreach (var model in Game1.currentInstance.models.Values)
|
||||||
|
foreach (var mesh in model.Meshes)
|
||||||
|
foreach (var effect in mesh.Effects)
|
||||||
|
if (effect is IEffectMatrices)
|
||||||
|
{
|
||||||
|
var meffect = effect as IEffectMatrices;
|
||||||
|
meffect.View = view;
|
||||||
|
}
|
||||||
|
Game1.currentInstance.terrain.View = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client.Entities
|
||||||
|
{
|
||||||
|
public class TerrainEntity : Entity
|
||||||
|
{
|
||||||
|
VertexPositionColor[] vertices;
|
||||||
|
short[] indices;
|
||||||
|
BasicEffect effect;
|
||||||
|
GraphicsDevice graphicsDevice;
|
||||||
|
|
||||||
|
public Matrix View { set { effect.View = value; } }
|
||||||
|
|
||||||
|
public TerrainEntity(int width, int height, GraphicsDevice graphicsDevice, Matrix projection) :
|
||||||
|
base()
|
||||||
|
{
|
||||||
|
this.graphicsDevice = graphicsDevice;
|
||||||
|
effect = new BasicEffect(this.graphicsDevice);
|
||||||
|
effect.Projection = projection;
|
||||||
|
effect.VertexColorEnabled = true;
|
||||||
|
|
||||||
|
vertices = new VertexPositionColor[width * height];
|
||||||
|
indices = new short[(width - 1) * (height - 1) * 6];
|
||||||
|
int currentIndex = 0;
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
for(int z = 0; z < height; z++)
|
||||||
|
{
|
||||||
|
vertices[x + z * width].Position = new Vector3(-8000 + (16000 / width * x), (float)Game1.random.NextDouble() * 50 - 50, -8000 + (16000 / height * z));
|
||||||
|
vertices[x + z * width].Color = new Color(Game1.random.Next(0, 255), Game1.random.Next(0, 255), Game1.random.Next(0, 255));
|
||||||
|
|
||||||
|
if(x < width - 1 && z < height - 1)
|
||||||
|
{
|
||||||
|
short downLeft = (short)(x + z * width);
|
||||||
|
short downRight = (short)((x + 1) + z * width);
|
||||||
|
short upLeft = (short)(x + (z + 1) * width);
|
||||||
|
short upRight = (short)((x + 1) + (z + 1) * width);
|
||||||
|
|
||||||
|
indices[currentIndex++] = downRight;
|
||||||
|
indices[currentIndex++] = upLeft;
|
||||||
|
indices[currentIndex++] = downLeft;
|
||||||
|
indices[currentIndex++] = upRight;
|
||||||
|
indices[currentIndex++] = upLeft;
|
||||||
|
indices[currentIndex++] = downRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(GameTime gameTime)
|
||||||
|
{
|
||||||
|
base.Draw(gameTime);
|
||||||
|
|
||||||
|
effect.CurrentTechnique.Passes[0].Apply();
|
||||||
|
graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
src/FluckyGame.Client/FluckyGame.Client/FluckyGame.Client.csproj
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectGuid>{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>FluckyGame.Client</RootNamespace>
|
||||||
|
<AssemblyName>FluckyGame.Client</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
|
||||||
|
<XnaPlatform>Windows</XnaPlatform>
|
||||||
|
<XnaProfile>HiDef</XnaProfile>
|
||||||
|
<XnaCrossPlatformGroupID>51098c2e-0727-4c82-8833-f5db8d6e4d2f</XnaCrossPlatformGroupID>
|
||||||
|
<XnaOutputType>Game</XnaOutputType>
|
||||||
|
<ApplicationIcon>Game.ico</ApplicationIcon>
|
||||||
|
<Thumbnail>GameThumbnail.png</Thumbnail>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\x86\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<NoStdLib>true</NoStdLib>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<XnaCompressContent>false</XnaCompressContent>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\x86\Release</OutputPath>
|
||||||
|
<DefineConstants>TRACE;WINDOWS</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<NoStdLib>true</NoStdLib>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<XnaCompressContent>true</XnaCompressContent>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.GamerServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Net" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Bone.cs" />
|
||||||
|
<Compile Include="Entities\BouncingEntity.cs" />
|
||||||
|
<Compile Include="Entities\Entity.cs" />
|
||||||
|
<Compile Include="Entities\TerrainEntity.cs" />
|
||||||
|
<Compile Include="Entities\ModelEntity.cs" />
|
||||||
|
<Compile Include="Entities\PlayerEntity.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Game1.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Game.ico" />
|
||||||
|
<Content Include="GameThumbnail.png">
|
||||||
|
<XnaPlatformSpecific>true</XnaPlatformSpecific>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\FluckyGame.Library\FluckyGame.Library.csproj">
|
||||||
|
<Project>{1cef270c-fce8-4bd1-920f-440d9cc8ed5b}</Project>
|
||||||
|
<Name>FluckyGame.Library</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\FluckyGame.Client.Pipeline\FluckyGame.Client.Pipeline.Animation\FluckyGame.Client.Pipeline.Animation.csproj">
|
||||||
|
<Project>{9975ed45-7a21-4f8a-9ec3-12f5845f681f}</Project>
|
||||||
|
<Name>FluckyGame.Client.Pipeline.Animation</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\FluckyGame.ClientContent\FluckyGame.ClientContent.contentproj">
|
||||||
|
<Name>FluckyGame.ClientContent</Name>
|
||||||
|
<XnaReferenceType>Content</XnaReferenceType>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 und x64%29</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Windows Installer 4.5</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.targets" />
|
||||||
|
<!--
|
||||||
|
To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
BIN
src/FluckyGame.Client/FluckyGame.Client/Game.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
362
src/FluckyGame.Client/FluckyGame.Client/Game1.cs
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using FluckyGame.Client.Entities;
|
||||||
|
using FluckyGame.Client.Pipeline.Animation;
|
||||||
|
using FluckyGame.Library;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client
|
||||||
|
{
|
||||||
|
public class Game1 : Microsoft.Xna.Framework.Game
|
||||||
|
{
|
||||||
|
public static Game1 currentInstance;
|
||||||
|
public static Random random;
|
||||||
|
|
||||||
|
SpriteBatch spriteBatch;
|
||||||
|
SpriteFont spriteFont;
|
||||||
|
|
||||||
|
public GraphicsDeviceManager graphicsDeviceManager;
|
||||||
|
|
||||||
|
public Dictionary<string, Model> models;
|
||||||
|
public Dictionary<Model, ModelExtra> modelExtras;
|
||||||
|
public Dictionary<Model, List<Bone>> modelBones;
|
||||||
|
|
||||||
|
public List<Entity> entities;
|
||||||
|
public Dictionary<string, ModelEntity> entitiesById;
|
||||||
|
public PlayerEntity player;
|
||||||
|
public TerrainEntity terrain;
|
||||||
|
|
||||||
|
bool[] last;
|
||||||
|
bool wireframe;
|
||||||
|
|
||||||
|
public Thread networkingThread;
|
||||||
|
public TcpClient tcpClient;
|
||||||
|
public NetworkStream networkStream;
|
||||||
|
private Queue<Packet> queue;
|
||||||
|
private bool exiting;
|
||||||
|
|
||||||
|
static Game1()
|
||||||
|
{
|
||||||
|
random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Game1(TcpClient tcpClient)
|
||||||
|
{
|
||||||
|
this.tcpClient = tcpClient;
|
||||||
|
|
||||||
|
currentInstance = this;
|
||||||
|
|
||||||
|
graphicsDeviceManager = new GraphicsDeviceManager(this)
|
||||||
|
{
|
||||||
|
PreferredBackBufferWidth = 1920 / 2,
|
||||||
|
PreferredBackBufferHeight = 1080 / 2
|
||||||
|
};
|
||||||
|
Content.RootDirectory = "Content";
|
||||||
|
|
||||||
|
IsMouseVisible = true;
|
||||||
|
|
||||||
|
last = new bool[] { false, false, false, false, false, false, false, false, false, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
spriteBatch = new SpriteBatch(GraphicsDevice);
|
||||||
|
spriteFont = Content.Load<SpriteFont>("SpriteFont");
|
||||||
|
|
||||||
|
models = new Dictionary<string, Model>();
|
||||||
|
modelExtras = new Dictionary<Model, ModelExtra>();
|
||||||
|
modelBones = new Dictionary<Model, List<Bone>>();
|
||||||
|
|
||||||
|
var projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 0.1f, 5000.0f);
|
||||||
|
foreach (var modelName in new[] { "box", "cone", "cylinder", "dude", "figure", "monkey", "sphere", "torus", "Victoria-hat-dance", "Victoria-hat-tpose" })
|
||||||
|
{
|
||||||
|
var model = Content.Load<Model>(Path.Combine("Models", modelName));
|
||||||
|
|
||||||
|
foreach (var mesh in model.Meshes)
|
||||||
|
{
|
||||||
|
foreach (var effect in mesh.Effects)
|
||||||
|
{
|
||||||
|
if (effect is IEffectMatrices)
|
||||||
|
(effect as IEffectMatrices).Projection = projection;
|
||||||
|
|
||||||
|
if (effect is IEffectLights)
|
||||||
|
(effect as IEffectLights).EnableDefaultLighting();
|
||||||
|
|
||||||
|
if (effect is BasicEffect)
|
||||||
|
(effect as BasicEffect).PreferPerPixelLighting = true;
|
||||||
|
|
||||||
|
if (effect is SkinnedEffect)
|
||||||
|
(effect as SkinnedEffect).PreferPerPixelLighting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
models.Add(modelName, model);
|
||||||
|
|
||||||
|
var bones = new List<Bone>();
|
||||||
|
foreach (ModelBone bone in model.Bones)
|
||||||
|
bones.Add(new Bone(bone.Name, bone.Transform, bone.Parent != null ? bones[bone.Parent.Index] : null));
|
||||||
|
modelBones.Add(model, bones);
|
||||||
|
|
||||||
|
if (model.Tag is ModelExtra)
|
||||||
|
{
|
||||||
|
var modelExtra = model.Tag as ModelExtra;
|
||||||
|
modelExtras.Add(model, modelExtra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var texture = Content.Load<Texture2D>(Path.Combine("Models", "figure_texture"));
|
||||||
|
foreach (var mesh in models["figure"].Meshes)
|
||||||
|
foreach (BasicEffect effect in mesh.Effects)
|
||||||
|
{
|
||||||
|
effect.Texture = texture;
|
||||||
|
effect.TextureEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
entities = new List<Entity>()
|
||||||
|
{
|
||||||
|
(player = new PlayerEntity()),
|
||||||
|
(terrain = new TerrainEntity(200, 200, GraphicsDevice, projection))
|
||||||
|
};
|
||||||
|
|
||||||
|
entitiesById = new Dictionary<string, ModelEntity>();
|
||||||
|
|
||||||
|
queue = new Queue<Packet>();
|
||||||
|
|
||||||
|
networkStream = this.tcpClient.GetStream();
|
||||||
|
|
||||||
|
networkingThread = new Thread(ReceivePackets);
|
||||||
|
networkingThread.IsBackground = true;
|
||||||
|
networkingThread.Start();
|
||||||
|
|
||||||
|
base.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReceivePackets()
|
||||||
|
{
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var packet = Packet.Receive(networkStream);
|
||||||
|
|
||||||
|
lock (queue)
|
||||||
|
queue.Enqueue(packet);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
if (!exiting)
|
||||||
|
{
|
||||||
|
System.Windows.Forms.MessageBox.Show("Verbindungsfehler:\n\n" + ex.Message, "Verbindungsfehler!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
|
||||||
|
Exit();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendPacket(Packet packet)
|
||||||
|
{
|
||||||
|
packet.Send(networkStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
lock(queue)
|
||||||
|
{
|
||||||
|
while(queue.Count > 0)
|
||||||
|
{
|
||||||
|
var packet = queue.Dequeue();
|
||||||
|
|
||||||
|
var type = (string)packet["type"];
|
||||||
|
if (type == "NEW")
|
||||||
|
{
|
||||||
|
var model = (string)packet["model"];
|
||||||
|
var position = (Vector3)packet["position"];
|
||||||
|
var rotation = (Vector3)packet["rotation"];
|
||||||
|
var scalation = (Vector3)packet["scalation"];
|
||||||
|
var entity = new ModelEntity(
|
||||||
|
models[model],
|
||||||
|
position,
|
||||||
|
rotation,
|
||||||
|
scalation
|
||||||
|
);
|
||||||
|
entities.Add(entity);
|
||||||
|
entitiesById.Add((string)packet["id"], entity);
|
||||||
|
}
|
||||||
|
else if(type == "REMOVE")
|
||||||
|
{
|
||||||
|
var id = (string)packet["id"];
|
||||||
|
entities.Remove(entitiesById[id]);
|
||||||
|
entitiesById.Remove(id);
|
||||||
|
}
|
||||||
|
else if (type == "UPDATE")
|
||||||
|
{
|
||||||
|
ModelEntity entity = entitiesById[(string)packet["id"]];
|
||||||
|
if (packet.ContainsKey("position"))
|
||||||
|
entity.Position = (Vector3)packet["position"];
|
||||||
|
if (packet.ContainsKey("rotation"))
|
||||||
|
entity.Rotation = (Vector3)packet["rotation"];
|
||||||
|
if (packet.ContainsKey("scalation"))
|
||||||
|
entity.Scalation = (Vector3)packet["scalation"];
|
||||||
|
entity.UpdateWorld();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Exception("Unknown packet type!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var kState = IsActive ? Keyboard.GetState() : new KeyboardState();
|
||||||
|
var mState = IsActive ? Mouse.GetState() : new MouseState();
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.Escape))
|
||||||
|
{
|
||||||
|
exiting = true;
|
||||||
|
networkingThread.Abort();
|
||||||
|
Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D1) && !last[0])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "box" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(25) }
|
||||||
|
});
|
||||||
|
last[0] = kState.IsKeyDown(Keys.D1);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D2) && !last[1])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "cone" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(25) }
|
||||||
|
});
|
||||||
|
last[1] = kState.IsKeyDown(Keys.D2);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D3) && !last[2])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "cylinder" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(25) }
|
||||||
|
});
|
||||||
|
last[2] = kState.IsKeyDown(Keys.D3);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D4) && !last[3])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "dude" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(1) }
|
||||||
|
});
|
||||||
|
last[3] = kState.IsKeyDown(Keys.D4);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D5) && !last[4])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "monkey" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(25) }
|
||||||
|
});
|
||||||
|
last[4] = kState.IsKeyDown(Keys.D5);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D6) && !last[5])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "sphere" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(25) }
|
||||||
|
});
|
||||||
|
last[5] = kState.IsKeyDown(Keys.D6);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D7) && !last[6])
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{ "type", "ADD" },
|
||||||
|
{ "model", "torus" },
|
||||||
|
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
|
||||||
|
{ "rotation", player.Rotation },
|
||||||
|
{ "scalation", new Vector3(25) }
|
||||||
|
});
|
||||||
|
last[6] = kState.IsKeyDown(Keys.D7);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D8) && !last[7])
|
||||||
|
entities.Add(new ModelEntity(models["Victoria-hat-tpose"], player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)), player.Rotation));
|
||||||
|
last[7] = kState.IsKeyDown(Keys.D8);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.D9) && !last[8])
|
||||||
|
{
|
||||||
|
var entity = new ModelEntity(models["Victoria-hat-tpose"], player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)), player.Rotation, new Vector3(0.4f));
|
||||||
|
entity.AnimationClip = modelExtras[models["Victoria-hat-dance"]].Clips[0];
|
||||||
|
entity.AnimationLooping = true;
|
||||||
|
entity.AnimationPlaying = true;
|
||||||
|
entities.Add(entity);
|
||||||
|
}
|
||||||
|
last[8] = kState.IsKeyDown(Keys.D9);
|
||||||
|
|
||||||
|
if (kState.IsKeyDown(Keys.R) && !last[9])
|
||||||
|
wireframe = !wireframe;
|
||||||
|
last[9] = kState.IsKeyDown(Keys.R);
|
||||||
|
|
||||||
|
foreach (var entity in entities)
|
||||||
|
entity.Update(gameTime, kState, mState);
|
||||||
|
|
||||||
|
base.Update(gameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(GameTime gameTime)
|
||||||
|
{
|
||||||
|
GraphicsDevice.Clear(Color.CornflowerBlue);
|
||||||
|
|
||||||
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
||||||
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
|
|
||||||
|
if(wireframe)
|
||||||
|
{
|
||||||
|
var rState = new RasterizerState();
|
||||||
|
rState.FillMode = FillMode.WireFrame;
|
||||||
|
GraphicsDevice.RasterizerState = rState;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entity in entities)
|
||||||
|
entity.Draw(gameTime);
|
||||||
|
|
||||||
|
spriteBatch.Begin();
|
||||||
|
|
||||||
|
{
|
||||||
|
var text = string.Format("{0} FPS", (int)(1000 / gameTime.ElapsedGameTime.TotalMilliseconds));
|
||||||
|
spriteBatch.DrawString(spriteFont, text, new Vector2(graphicsDeviceManager.PreferredBackBufferWidth - spriteFont.MeasureString(text).X, 0), Color.White);
|
||||||
|
}
|
||||||
|
|
||||||
|
spriteBatch.DrawString(spriteFont, string.Format("Player: Position: {0:F2}, {1:F2}, {2:F2} Rotation: {3:F2} {4:F2} {5:F2}", player.Position.X, player.Position.Y, player.Position.Z, player.Rotation.X, player.Rotation.Y, player.Rotation.Z), Vector2.Zero, Color.White);
|
||||||
|
|
||||||
|
spriteBatch.DrawString(spriteFont, "Press any key to spawn entity:", new Vector2(0, 40), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "1 - Box", new Vector2(0, 60), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "2 - Cone", new Vector2(0, 80), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "3 - Cylinder", new Vector2(0, 100), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "4 - Dude", new Vector2(0, 120), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "5 - Monkey", new Vector2(0, 140), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "6 - Sphere", new Vector2(0, 160), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "7 - Torus", new Vector2(0, 180), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "8 - Victoria (not synced)", new Vector2(0, 200), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, "9 - Victoria (dancing) (not synced)", new Vector2(0, 220), Color.White);
|
||||||
|
spriteBatch.DrawString(spriteFont, string.Format("{0} entities", entities.Count), new Vector2(0, 260), Color.White);
|
||||||
|
|
||||||
|
spriteBatch.End();
|
||||||
|
|
||||||
|
base.Draw(gameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
src/FluckyGame.Client/FluckyGame.Client/GameThumbnail.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
28
src/FluckyGame.Client/FluckyGame.Client/Program.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace FluckyGame.Client
|
||||||
|
{
|
||||||
|
static class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
TcpClient tcpClient;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tcpClient = new TcpClient("home.brunner.ninja", 8001);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Konnte keine Verbindung herstellen:\n\n" + ex.Message, "Konnte keine Verbindung herstellen!", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (Game1 game = new Game1(tcpClient))
|
||||||
|
game.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("FluckyGame.Client")]
|
||||||
|
[assembly: AssemblyProduct("FluckyGame.Client")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type. Only Windows
|
||||||
|
// assemblies support COM.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// On Windows, the following GUID is for the ID of the typelib if this
|
||||||
|
// project is exposed to COM. On other platforms, it unique identifies the
|
||||||
|
// title storage container when deploying this assembly to the device.
|
||||||
|
[assembly: Guid("8cad4fa5-8d97-4c56-83af-8f305e78f60b")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
@@ -0,0 +1,140 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectGuid>{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
|
||||||
|
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
||||||
|
<ContentRootDirectory>Content</ContentRootDirectory>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>FluckyGame.ClientContent</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.EffectImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.FBXImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.XImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.AudioImporters, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.VideoImporters, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="SpriteFont.spritefont">
|
||||||
|
<Name>SpriteFont</Name>
|
||||||
|
<Importer>FontDescriptionImporter</Importer>
|
||||||
|
<Processor>FontDescriptionProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Models\box.fbx">
|
||||||
|
<Name>box</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Models\cone.fbx">
|
||||||
|
<Name>cone</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Models\cylinder.fbx">
|
||||||
|
<Name>cylinder</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Models\monkey.fbx">
|
||||||
|
<Name>monkey</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Models\sphere.fbx">
|
||||||
|
<Name>sphere</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Models\torus.fbx">
|
||||||
|
<Name>torus</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Models\Victoria-hat-tpose.FBX">
|
||||||
|
<Name>Victoria-hat-tpose</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Models\Victoria-hat-dance.FBX">
|
||||||
|
<Name>Victoria-hat-dance</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FluckyGame.Client.Pipeline\FluckyGame.Client.Pipeline.Animation\FluckyGame.Client.Pipeline.Animation.csproj">
|
||||||
|
<Project>{9975ed45-7a21-4f8a-9ec3-12f5845f681f}</Project>
|
||||||
|
<Name>FluckyGame.Client.Pipeline.Animation</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Models\dude.fbx">
|
||||||
|
<Name>dude</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>AnimationProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Models\figure.fbx">
|
||||||
|
<Name>figure</Name>
|
||||||
|
<Importer>FbxImporter</Importer>
|
||||||
|
<Processor>ModelProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
<None Include="Models\head.tga">
|
||||||
|
<Name>head</Name>
|
||||||
|
<Importer>TextureImporter</Importer>
|
||||||
|
<Processor>TextureProcessor</Processor>
|
||||||
|
</None>
|
||||||
|
<None Include="Models\jacket.tga">
|
||||||
|
<Name>jacket</Name>
|
||||||
|
<Importer>TextureImporter</Importer>
|
||||||
|
<Processor>TextureProcessor</Processor>
|
||||||
|
</None>
|
||||||
|
<None Include="Models\pants.tga">
|
||||||
|
<Name>pants</Name>
|
||||||
|
<Importer>TextureImporter</Importer>
|
||||||
|
<Processor>TextureProcessor</Processor>
|
||||||
|
</None>
|
||||||
|
<None Include="Models\upBodyC.tga">
|
||||||
|
<Name>upBodyC</Name>
|
||||||
|
<Importer>TextureImporter</Importer>
|
||||||
|
<Processor>TextureProcessor</Processor>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Models\figure_texture.png">
|
||||||
|
<Name>figure_texture</Name>
|
||||||
|
<Importer>TextureImporter</Importer>
|
||||||
|
<Processor>TextureProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
After Width: | Height: | Size: 1.2 MiB |
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/box.fbx
Normal file
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/cone.fbx
Normal file
72565
src/FluckyGame.Client/FluckyGame.ClientContent/Models/dude.fbx
Normal file
7450
src/FluckyGame.Client/FluckyGame.ClientContent/Models/figure.fbx
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/head.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/jacket.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/monkey.fbx
Normal file
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/pants.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/sphere.fbx
Normal file
BIN
src/FluckyGame.Client/FluckyGame.ClientContent/Models/torus.fbx
Normal file
After Width: | Height: | Size: 3.0 MiB |
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
This file contains an xml description of a font, and will be read by the XNA
|
||||||
|
Framework Content Pipeline. Follow the comments to customize the appearance
|
||||||
|
of the font in your game, and to change the characters which are available to draw
|
||||||
|
with.
|
||||||
|
-->
|
||||||
|
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
|
||||||
|
<Asset Type="Graphics:FontDescription">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Modify this string to change the font that will be imported.
|
||||||
|
-->
|
||||||
|
<FontName>Segoe UI Mono</FontName>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Size is a float value, measured in points. Modify this value to change
|
||||||
|
the size of the font.
|
||||||
|
-->
|
||||||
|
<Size>14</Size>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Spacing is a float value, measured in pixels. Modify this value to change
|
||||||
|
the amount of spacing in between characters.
|
||||||
|
-->
|
||||||
|
<Spacing>0</Spacing>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
UseKerning controls the layout of the font. If this value is true, kerning information
|
||||||
|
will be used when placing characters.
|
||||||
|
-->
|
||||||
|
<UseKerning>true</UseKerning>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
|
||||||
|
and "Bold, Italic", and are case sensitive.
|
||||||
|
-->
|
||||||
|
<Style>Regular</Style>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
If you uncomment this line, the default character will be substituted if you draw
|
||||||
|
or measure text that contains characters which were not included in the font.
|
||||||
|
-->
|
||||||
|
<!-- <DefaultCharacter>*</DefaultCharacter> -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
CharacterRegions control what letters are available in the font. Every
|
||||||
|
character from Start to End will be built and made available for drawing. The
|
||||||
|
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
|
||||||
|
character set. The characters are ordered according to the Unicode standard.
|
||||||
|
See the documentation for more information.
|
||||||
|
-->
|
||||||
|
<CharacterRegions>
|
||||||
|
<CharacterRegion>
|
||||||
|
<Start> </Start>
|
||||||
|
<End>~</End>
|
||||||
|
</CharacterRegion>
|
||||||
|
</CharacterRegions>
|
||||||
|
</Asset>
|
||||||
|
</XnaContent>
|
55
src/FluckyGame.Library/FluckyGame.Library.csproj
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>FluckyGame.Library</RootNamespace>
|
||||||
|
<AssemblyName>FluckyGame.Library</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Packet.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
49
src/FluckyGame.Library/Packet.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
|
|
||||||
|
namespace FluckyGame.Library
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class Packet : Dictionary<string, object>
|
||||||
|
{
|
||||||
|
private static readonly IFormatter formatter;
|
||||||
|
|
||||||
|
static Packet()
|
||||||
|
{
|
||||||
|
formatter = new BinaryFormatter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Packet() : base() { }
|
||||||
|
|
||||||
|
public Packet(int capacity) : base(capacity) { }
|
||||||
|
|
||||||
|
public Packet(IEqualityComparer<string> comparer) : base(comparer) { }
|
||||||
|
|
||||||
|
public Packet(IDictionary<string, object> dictionary) : base(dictionary) { }
|
||||||
|
|
||||||
|
public Packet(int capacity, IEqualityComparer<string> comparer) : base(capacity, comparer) { }
|
||||||
|
|
||||||
|
public Packet(IDictionary<string, object> dictionary, IEqualityComparer<string> comparer) : base(dictionary, comparer) { }
|
||||||
|
|
||||||
|
public Packet(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||||
|
|
||||||
|
public static Packet Receive(Stream stream)
|
||||||
|
{
|
||||||
|
var obj = formatter.Deserialize(stream);
|
||||||
|
|
||||||
|
var packet = obj as Packet;
|
||||||
|
if (packet == null)
|
||||||
|
throw new Exception("no packet received!");
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(Stream stream)
|
||||||
|
{
|
||||||
|
formatter.Serialize(stream, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
src/FluckyGame.Library/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||||
|
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||||
|
// die einer Assembly zugeordnet sind.
|
||||||
|
[assembly: AssemblyTitle("FluckyGame.Library")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("FluckyGame.Library")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
|
||||||
|
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
|
||||||
|
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||||
|
[assembly: Guid("1cef270c-fce8-4bd1-920f-440d9cc8ed5b")]
|
||||||
|
|
||||||
|
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||||
|
//
|
||||||
|
// Hauptversion
|
||||||
|
// Nebenversion
|
||||||
|
// Buildnummer
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
||||||
|
// übernehmen, indem Sie "*" eingeben:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
6
src/FluckyGame.Server/App.config
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
40
src/FluckyGame.Server/BouncingEntity.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using FluckyGame.Library;
|
||||||
|
|
||||||
|
namespace FluckyGame.Server
|
||||||
|
{
|
||||||
|
class BouncingEntity : Entity
|
||||||
|
{
|
||||||
|
private float ySpeed;
|
||||||
|
|
||||||
|
const float randomMin = 1;
|
||||||
|
const float randomMax = 5;
|
||||||
|
|
||||||
|
public BouncingEntity(string id, string model, Vector3 position, Vector3 rotation, Vector3 scalation) :
|
||||||
|
base(id, model, position, rotation, scalation)
|
||||||
|
{
|
||||||
|
ySpeed = ((float)Program.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (Position.Y > 0)
|
||||||
|
ySpeed -= 0.1f;
|
||||||
|
else
|
||||||
|
ySpeed = ((float)Program.random.NextDouble() * (randomMax - randomMin)) + randomMin;
|
||||||
|
|
||||||
|
Position.Y += ySpeed;
|
||||||
|
|
||||||
|
lock (Program.clients)
|
||||||
|
foreach (var client in Program.clients)
|
||||||
|
client.SendPacket(new Packet() {
|
||||||
|
{"type", "UPDATE" },
|
||||||
|
{"id", Id },
|
||||||
|
{"position", Position }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
src/FluckyGame.Server/Client.cs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using FluckyGame.Library;
|
||||||
|
|
||||||
|
namespace FluckyGame.Server
|
||||||
|
{
|
||||||
|
internal class Client
|
||||||
|
{
|
||||||
|
TcpClient tcpClient;
|
||||||
|
NetworkStream networkStream;
|
||||||
|
Thread thread;
|
||||||
|
bool disconnecting;
|
||||||
|
|
||||||
|
Entity playerEntity;
|
||||||
|
|
||||||
|
public Client(TcpClient tcpClient)
|
||||||
|
{
|
||||||
|
Console.WriteLine("New connection from {0}", tcpClient.Client.RemoteEndPoint);
|
||||||
|
this.tcpClient = tcpClient;
|
||||||
|
this.networkStream = this.tcpClient.GetStream();
|
||||||
|
|
||||||
|
lock (Program.entities)
|
||||||
|
{
|
||||||
|
foreach (var entity in Program.entities)
|
||||||
|
SendPacket(new Packet() {
|
||||||
|
{"type", "NEW" },
|
||||||
|
{"id", entity.Id },
|
||||||
|
{"model", entity.Model },
|
||||||
|
{"position", entity.Position },
|
||||||
|
{"rotation", entity.Rotation },
|
||||||
|
{"scalation", entity.Scalation }
|
||||||
|
});
|
||||||
|
|
||||||
|
Program.entities.Add(playerEntity = new Entity(Guid.NewGuid().ToString(), "dude", Vector3.Zero, Vector3.Zero, new Vector3(1)));
|
||||||
|
|
||||||
|
lock (Program.clients)
|
||||||
|
foreach (var client in Program.clients)
|
||||||
|
if(client != this)
|
||||||
|
client.SendPacket(new Packet() {
|
||||||
|
{"type", "NEW" },
|
||||||
|
{"id", playerEntity.Id },
|
||||||
|
{"model", playerEntity.Model },
|
||||||
|
{"position", playerEntity.Position },
|
||||||
|
{"rotation", playerEntity.Rotation },
|
||||||
|
{"scalation", playerEntity.Scalation }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
thread = new Thread(ReceivePackets);
|
||||||
|
thread.IsBackground = true;
|
||||||
|
thread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReceivePackets()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var packet = Packet.Receive(networkStream);
|
||||||
|
|
||||||
|
var type = (string)packet["type"];
|
||||||
|
|
||||||
|
if (type == "ADD")
|
||||||
|
{
|
||||||
|
lock (Program.entities)
|
||||||
|
{
|
||||||
|
var entity = new Entity(
|
||||||
|
Guid.NewGuid().ToString(),
|
||||||
|
(string)packet["model"],
|
||||||
|
(Vector3)packet["position"],
|
||||||
|
(Vector3)packet["rotation"],
|
||||||
|
(Vector3)packet["scalation"]
|
||||||
|
);
|
||||||
|
|
||||||
|
Program.entities.Add(entity);
|
||||||
|
|
||||||
|
lock (Program.clients)
|
||||||
|
foreach (var client in Program.clients)
|
||||||
|
client.SendPacket(new Packet() {
|
||||||
|
{"type", "NEW" },
|
||||||
|
{"id", entity.Id },
|
||||||
|
{"model", entity.Model },
|
||||||
|
{"position", entity.Position },
|
||||||
|
{"rotation", entity.Rotation },
|
||||||
|
{"scalation", entity.Scalation }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == "PLAYER")
|
||||||
|
{
|
||||||
|
playerEntity.Position = (Vector3)packet["position"];
|
||||||
|
playerEntity.Rotation = (Vector3)packet["rotation"];
|
||||||
|
|
||||||
|
lock (Program.clients)
|
||||||
|
foreach (var client in Program.clients)
|
||||||
|
if(client != this)
|
||||||
|
client.SendPacket(new Packet() {
|
||||||
|
{"type", "UPDATE" },
|
||||||
|
{"id", playerEntity.Id },
|
||||||
|
{"position", playerEntity.Position },
|
||||||
|
{"rotation", playerEntity.Rotation }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Exception("Unknown packet type!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
if(!disconnecting)
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
lock (Program.clients)
|
||||||
|
Program.clients.Remove(this);
|
||||||
|
lock (Program.entities)
|
||||||
|
Program.entities.Remove(playerEntity);
|
||||||
|
lock (Program.clients)
|
||||||
|
foreach (var client in Program.clients)
|
||||||
|
client.SendPacket(new Packet() {
|
||||||
|
{ "type", "REMOVE" },
|
||||||
|
{ "id", playerEntity.Id }
|
||||||
|
});
|
||||||
|
networkStream.Dispose();
|
||||||
|
tcpClient.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendPacket(Packet packet)
|
||||||
|
{
|
||||||
|
if (disconnecting)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//TODO: lock to avoid message mixing (one message sending while other)
|
||||||
|
packet.Send(networkStream);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
disconnecting = true;
|
||||||
|
thread.Abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/FluckyGame.Server/Entity.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace FluckyGame.Server
|
||||||
|
{
|
||||||
|
class Entity
|
||||||
|
{
|
||||||
|
public string Id;
|
||||||
|
public string Model;
|
||||||
|
public Vector3 Position;
|
||||||
|
public Vector3 Rotation;
|
||||||
|
public Vector3 Scalation;
|
||||||
|
|
||||||
|
public Entity(string id, string model, Vector3 position, Vector3 rotation, Vector3 scalation)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Model = model;
|
||||||
|
Position = position;
|
||||||
|
Rotation = rotation;
|
||||||
|
Scalation = scalation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Update() { }
|
||||||
|
}
|
||||||
|
}
|
71
src/FluckyGame.Server/FluckyGame.Server.csproj
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{85507C7D-93AB-4344-9290-4A79396C083E}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>FluckyGame.Server</RootNamespace>
|
||||||
|
<AssemblyName>FluckyGame.Server</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="BouncingEntity.cs" />
|
||||||
|
<Compile Include="Client.cs" />
|
||||||
|
<Compile Include="Entity.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FluckyGame.Library\FluckyGame.Library.csproj">
|
||||||
|
<Project>{1cef270c-fce8-4bd1-920f-440d9cc8ed5b}</Project>
|
||||||
|
<Name>FluckyGame.Library</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
89
src/FluckyGame.Server/Program.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace FluckyGame.Server
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
internal static List<Client> clients;
|
||||||
|
|
||||||
|
private static Thread acceptThread;
|
||||||
|
|
||||||
|
internal static Random random;
|
||||||
|
internal static List<Entity> entities;
|
||||||
|
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Initializing FluckyGame Server 1.0...");
|
||||||
|
|
||||||
|
clients = new List<Client>();
|
||||||
|
|
||||||
|
acceptThread = new Thread(AcceptConnections);
|
||||||
|
acceptThread.IsBackground = true;
|
||||||
|
acceptThread.Start();
|
||||||
|
|
||||||
|
//Game Server Initialization
|
||||||
|
random = new Random();
|
||||||
|
entities = new List<Entity>();
|
||||||
|
|
||||||
|
const int testSize = 200;
|
||||||
|
const int testStep = 50;
|
||||||
|
for (var z = -testSize; z <= testSize; z += testStep)
|
||||||
|
for (var x = -testSize; x <= testSize; x += testStep)
|
||||||
|
{
|
||||||
|
entities.Add(new BouncingEntity(
|
||||||
|
Guid.NewGuid().ToString(),
|
||||||
|
(new List<string>() { "box", "cone", "cylinder", "figure", "monkey", "sphere", "torus" }).OrderBy(o => random.Next()).First(),
|
||||||
|
new Vector3(x, 50, z),
|
||||||
|
Vector3.Zero,
|
||||||
|
new Vector3(5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const int minTime = 1000 / 60; //60 FPS
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
var dateTime = DateTime.Now;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var started = DateTime.Now;
|
||||||
|
|
||||||
|
var changedEntities = new List<Entity>();
|
||||||
|
|
||||||
|
lock (entities)
|
||||||
|
{
|
||||||
|
foreach (var entity in entities)
|
||||||
|
entity.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
if((DateTime.Now - dateTime).TotalSeconds >= 1)
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0} Updates per Second ({1} clients)", count, clients.Count);
|
||||||
|
count = 0;
|
||||||
|
dateTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
int elapsed = (int)(DateTime.Now - started).TotalMilliseconds;
|
||||||
|
if (elapsed < minTime)
|
||||||
|
Thread.Sleep(minTime - elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AcceptConnections()
|
||||||
|
{
|
||||||
|
var listener = new TcpListener(IPAddress.Any, 8001);
|
||||||
|
listener.Start();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var client = new Client(listener.AcceptTcpClient());
|
||||||
|
lock(clients)
|
||||||
|
clients.Add(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
src/FluckyGame.Server/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||||
|
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||||
|
// die einer Assembly zugeordnet sind.
|
||||||
|
[assembly: AssemblyTitle("FluckyGame.Server")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("FluckyGame.Server")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
|
||||||
|
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
|
||||||
|
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||||
|
[assembly: Guid("85507c7d-93ab-4344-9290-4a79396c083e")]
|
||||||
|
|
||||||
|
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||||
|
//
|
||||||
|
// Hauptversion
|
||||||
|
// Nebenversion
|
||||||
|
// Buildnummer
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
|
||||||
|
// übernehmen, indem Sie "*" eingeben:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
68
src/FluckyGame.sln
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 14
|
||||||
|
VisualStudioVersion = 14.0.25420.1
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Client", "FluckyGame.Client\FluckyGame.Client\FluckyGame.Client.csproj", "{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.ClientContent", "FluckyGame.Client\FluckyGame.ClientContent\FluckyGame.ClientContent.contentproj", "{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FluckyGame.Client.Pipeline", "FluckyGame.Client.Pipeline", "{84CFF729-9434-4313-80E9-38853290643D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Client.Pipeline.Animation", "FluckyGame.Client\FluckyGame.Client.Pipeline\FluckyGame.Client.Pipeline.Animation\FluckyGame.Client.Pipeline.Animation.csproj", "{9975ED45-7A21-4F8A-9EC3-12F5845F681F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Server", "FluckyGame.Server\FluckyGame.Server.csproj", "{85507C7D-93AB-4344-9290-4A79396C083E}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Library", "FluckyGame.Library\FluckyGame.Library.csproj", "{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|Any CPU.Build.0 = Debug|x86
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Release|x86.Build.0 = Release|x86
|
||||||
|
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|Any CPU.Build.0 = Debug|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|Any CPU.Build.0 = Release|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|x86.Build.0 = Release|x86
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{9975ED45-7A21-4F8A-9EC3-12F5845F681F} = {84CFF729-9434-4313-80E9-38853290643D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|