I'm trying to make a realistic transition between a walking animation and the falling process with a ragdoll. Basically when calling the "DoRagdoll" function, I'm adding the previous force from the walking animation to all rigidbody components in respect of their masses. Then I deactivate the animator component and turn on gravity for all rigidbodies. It works but it still kinda looks weird. I already tried a lot like the Unity documentation site for problems with ragdolls and I also played around with the joints of the different bodyparts. I used the buildin system to create the ragdoll. Any Ideas on how to improve the transition or how to create a more realistic ragdoll?
void Awake()
{
rbs = GetComponentsInChildren<Rigidbody>();
DoRagdoll(false);
foreach (Rigidbody rb in rbs)
{
rb.useGravity = false;
//rb.isKinematic = true;
}
}
public void DoRagdoll (bool isRagdoll)
{
if (isRagdoll)
{
foreach (Rigidbody rb in rbs)
{
rb.AddForce(rb.mass * rb.velocity, ForceMode.Impulse);
}
}
GetComponent<Animator>().enabled = !isRagdoll;
if (isRagdoll)
{
foreach (Rigidbody rb in rbs)
{
rb.maxDepenetrationVelocity = 0.01f;
rb.useGravity = true;
//rb.isKinematic = false;
}
NavMeshAgent agent = GetComponent<NavMeshAgent>();
//GameObject.FindGameObjectWithTag("pelvis").GetComponent<PelvisPush>().PushPelvis();
rbSlowdown = true;
ragdollOn = true;
}
else
{
GetComponent<NavMeshAgent>().speed = GameObject.FindGameObjectWithTag("root").GetComponent<OldmanMovement>().movSpeed;
foreach (Rigidbody rb in rbs)
{
rb.useGravity = false;
//rb.isKinematic = true;
}
ragdollOn = false;
}
}
Related
Could someone please maybe download and see my project? It is very simple, but not working as in the tutorial.
In my project, I set IsTrigger to true in either the ThirdPersonController or the AIThirdPersonController for one of the characters. This makes the character fall down from the Plane.
I also changed one of the characters to be tagged as Player and changed the state from PATROL to CHASE but that changed nothing. The other player never chases/follows the player I am controlling and moving around.
Why are the players falling down when I set IsTrigger to true in my project?
I see in the video that the instructor is using a Maze Plane. Is that a package I should import in the Assets or is it already somewhere in the Assets? I just added regular Plane for now because I could not find a Maze Plane.
Here is a link for my project from my OneDrive. The file name is Demo AI.rar:
Project in OneDrive
Here is a link for the video tutorial I am attempting to follow. It is supposes to be simple I suppose:
Tutorial
Here is the BasicAi class I'm using in my project, the same script from the tutorial video:
using System.Collections;
using UnityStandardAssets.Characters.ThirdPerson;
public class BasicAi : MonoBehaviour {
public NavMeshAgent agent;
public ThirdPersonCharacter character;
public enum State {
PATROL,
CHASE
}
public State state;
private bool alive;
// Variables for patrolling
public GameObject[] waypoints;
private int waypointInd = 0;
public float patrolSpeed = 0.5f;
// Variable for chasing
public float chaseSpeed = 1f;
public GameObject target;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
character = GetComponent<ThirdPersonCharacter>();
agent.updatePosition = true;
agent.updateRotation = false;
state = BasicAi.State.PATROL;
alive = true;
StartCoroutine ("FSM");
}
IEnumerator FSM()
{
while (alive)
{
switch (state)
{
case State.PATROL:
Patrol ();
break;
case State.CHASE:
Chase ();
break;
}
yield return null;
}
}
void Patrol()
{
agent.speed = patrolSpeed;
if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) >= 2) {
agent.SetDestination (waypoints [waypointInd].transform.position);
character.Move (agent.desiredVelocity, false, false);
} else if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) <= 2) {
waypointInd += 1;
if (waypointInd > waypoints.Length) {
waypointInd = 0;
}
}
else
{
character.Move (Vector3.zero, false, false);
}
}
void Chase()
{
agent.speed = chaseSpeed;
agent.SetDestination (target.transform.position);
character.Move (agent.desiredVelocity, false, false);
}
void OnTriggerEnter(Collider coll)
{
if (coll.tag == "Player")
{
state = BasicAi.State.CHASE;
target = coll.gameObject;
}
}
}
Once a collider is a trigger it no longer collides with objects, your best bet is to place a child object that has a collider and setting that to the trigger, this way the original collider will still collide with your ground.
As for your other question how are you referencing your third person character, are you dragging it from the scene into the inspector, and you also have to bake your navmesh into your scene. I haven't looked at your project as that would take a lot of time, but maybe go through the tutorial again and see how they reference the character. With the inbuilt characters you normally have to access the namespace first.
Ive been following this article online and have swapped a few names and tags about but I dont seem to see any text appearing on the screen...
Here is my PlayerCollision script:
#pragma strict
function Update () {
}
function OnControllerColliderHit(hit : ControllerColliderHit){
if(hit.gameObject.tag == "Collider"){
ShowMessage.message = "HELLO WORLD";
ShowMessage.turnTextOn = true;
}
}
This is my ShowMessage script:
#pragma strict
static var turnTextOn : boolean = false;
static var message : String;
private var timer : float = 0.0;
function Start(){
timer = 0.0;
turnTextOn = false;
guiText.text = "";
}
function Update () {
if(turnTextOn){
guiText.enabled = true;
guiText.text = message;
timer += Time.deltaTime;
}
if(timer >= 5){
turnTextOn = false;
guiText.enabled = false;
timer = 0.0;
}
}
I have linked the ShowMessage script to my GUIText object and have linked the PlayerCollision script with the CharacterController. There is also a box collider object with the Collision tag I also Have the GUIText in view just to rule that out.
Anyone any idea what is wrong? Thanks
The tag should be "Collider" not "Collision" because if(hit.gameObject.tag == "Collider")
Problem solved. Turns out I ticked isTrigger which stopped the collision from being detected. This gives the problem of the character not being able to move through the object. What i did was tick the isTrigger option and change OnControllerColliderHit(hit : ControllerColliderHit) to OnTriggerEnter (obj : Collider)
im working with windows phone game using xna... and looking a way to make my object to move with holding some rectangle that i made as a button on screen....
i already tried this but it just read tap gesture only
foreach (GestureSample gestureSample in input.Gestures)
{
switch (gestureSample.GestureType)
{
case GestureType.Hold:
case GestureType.Tap:
Point tapLocation = new Point((int)gestureSample.Position.X, (int)gestureSample.Position.Y);
if (rightRectangle.Contains(tapLocation))
{
rightTouched = true;
player.Catapult.CurrentState = CatapultState.MoveRight;
playerPositionUpdate.X += 20;
player.catapultPosition.X += 20;
player.Catapult.catapultPosition.X += 20;
player.Catapult.projectilePositionUpdate.X += 20;
if (player.Catapult.catapultPosition.X == player.Catapult.catapultPosition.X + 20)
rightTouched = false;
CenterOnPosition(player.Catapult.Position - catapultCenterOffset);
}
break;
}
}
Gestures are discrete events. You want to poll the state of the touch panel every frame. Use TouchPanel.GetState() for that.
See Working with Touch Input (Windows Phone) for information.
As mentioned above you shouldn't use GestureSample for that purpose, because using dragcomplete and freedrag a bit tricky. Instead you should code your own gestures using TouchPanel.GetState()
TouchCollection touchCollection = TouchPanel.GetState();
if (touchCollection.Count == 1)
{
var touch = touchCollection[0];
switch (touch.State)
{
case TouchLocationState.Pressed:
if (rectangle.Contains((int) touch.Position.X, (int) touch.Position.Y))
{
isMoving = true;
}
break;
case TouchLocationState.Moved:
if (isMoving)
{
TouchLocation prevLocation;
touch.TryGetPreviousLocation(out prevLocation);
if (prevLocation.Position != touch.Position)
{
Vector2 delta = touch.Position - prevLocation.Position;
//offset your rectangle on delta
}
}
break;
case TouchLocationState.Released:
isMoving = false;
break;
}
}
else if (touchCollection.Count == 2)
{
var touchOne = touchCollection[0];
var touchTwo = touchCollection[1];
//pinch logic here
}
I guess you understand the idea.
I'm aware there are a lot of questions on this topic, and I've looked through most of them as well as Googling to help me solve this problem, to no avail.
What I'd like to do is post the relevant sections of my code that produce bitmaps and render bitmaps onto PictureBoxes in my UI, and I would like to know if anyone can spot what is specifically causing this error, and can suggest how to avoid or bypass it.
I'll start with the relevant bits (3) in my VideoRenderer class:
The timer event that continously calls MoveFrameToBitmap while video is running:
private void TimerTick(object sender, EventArgs e)
{
if (frameTransport.IsNewFrameAvailable())
{
if (frameTransport.GetFrame())
{
if (MoveFrameToBitmap())
{
double msSinceLastFrame = (Int32)DateTime.Now.Subtract(lastFrameTimestamp).TotalMilliseconds;
fps = 1000 / msSinceLastFrame;
lastFrameTimestamp = DateTime.Now;
}
}
else
{
if (frameTransport.channelKeyBufferBufidMismatch)
{
needsRestart = true;
}
}
}
}
MoveFrameToBitmap, which marshals in a video frame from FrameTransport, creates a bitmap if successful, clones it and queues the frame:
internal bool MoveFrameToBitmap()
{
bool result = false;
try
{
if (frameTransport.bitmapDataSize == 0)
{
return false;
}
bool ResolutionHasChanged = ((videoWidth != frameTransport.width) | (videoHeight != frameTransport.height));
videoHeight = frameTransport.height;
videoWidth = frameTransport.width;
Bitmap bitmap = new System.Drawing.Bitmap(videoWidth, videoHeight);
Rectangle rectangle = new System.Drawing.Rectangle(0, 0, videoWidth, videoHeight);
BitmapData bitmapData = new System.Drawing.Imaging.BitmapData();
bitmapData.Width = videoWidth;
bitmapData.Height = videoHeight;
bitmapData.PixelFormat = PixelFormat.Format24bppRgb;
bitmap.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb, bitmapData);
Marshal.Copy(frameTransport.bitmapData, 0, bitmapData.Scan0, frameTransport.bitmapDataSize);
lock (frameQueueLock)
{
if (frameQueue.Count == 0)
{
frameQueue.Enqueue(bitmap.Clone());
}
}
bitmap.UnlockBits(bitmapData);
if (ResolutionHasChanged) skypeRef.events.FireOnVideoResolutionChanged(this, new RootEvents.OnVideoResolutionChangedArgs(videoWidth, videoHeight));
bitmap.Dispose();
result = true;
}
catch (Exception) { }
GC.Collect();
return result;
}
The property that exposes the queued frame, which can be safely accessed even when a frame is not currently queued:
public Bitmap QueuedFrame
{
get
{
try
{
lock (frameQueueLock)
{
return frameQueue.Dequeue() as Bitmap;
}
}
catch (Exception)
{
return null;
}
}
}
That's all for VideoRenderer. Now I'll show the relevant property of the static MyVideo class, which encapsulates, controls and returns frames from two video renderers. Here is the property which exposes the queued frame of the first renderer (every call to videoPreviewRenderer is locked with VPR_Lock):
public static Bitmap QueuedVideoPreviewFrame
{
get
{
lock (VPR_Lock) { return videoPreviewRenderer.QueuedFrame; }
}
}
The property for the second renderer is the same, except with its own lock object.
Moving on, here is the thread and its call in my UI that accesses the two queued frame properties in MyVideo and renders frames to the two PictureBoxes:
ThreadStart renderVCONF3501VideoThreadStart = new ThreadStart(new Action(() =>
{
while (MyAccount.IsLoggedIn)
{
if (MyVideo.VideoPreviewIsRendering)
{
if (MyVideo.VideoPreviewRenderer.NeedsRestart)
{
MyVideo.VideoPreviewRenderer.Stop();
MyVideo.VideoPreviewRenderer.Start();
MyVideo.VideoPreviewRenderer.NeedsRestart = false;
}
else
{
try
{
Bitmap newVideoPreviewFrame = MyVideo.QueuedVideoPreviewFrame;
if (newVideoPreviewFrame != null)
{
lock (VCONF3501_VPI_Lock)
{
VCONF3501_VideoPreview.Image = newVideoPreviewFrame;
}
}
}
catch (Exception) { continue; }
}
}
else
{
lock (VCONF3501_VPI_Lock)
{
VCONF3501_VideoPreview.Image = null;
}
}
if (MyVideo.LiveSessionParticipantVideoIsRendering)
{
if (MyVideo.LiveSessionParticipantVideoRenderer.NeedsRestart)
{
MyVideo.LiveSessionParticipantVideoRenderer.Stop();
MyVideo.LiveSessionParticipantVideoRenderer.Start();
MyVideo.LiveSessionParticipantVideoRenderer.NeedsRestart = false;
}
else
{
try
{
Bitmap newLiveSessionParticipantVideoFrame = MyVideo.QueuedLiveSessionParticipantVideoFrame;
if (newLiveSessionParticipantVideoFrame != null)
{
lock (VCONF3501_LSPVI_Lock)
{
VCONF3501_Video.Image = newLiveSessionParticipantVideoFrame;
}
}
}
catch (Exception) { continue; }
}
}
else
{
lock (VCONF3501_LSPVI_Lock)
{
VCONF3501_Video.Image = null;
}
}
GC.Collect();
}
}));
new Thread(renderVCONF3501VideoThreadStart).Start();
The GC.Collect() calls are to force bitmap memory release, as there was a memory leak (and still might be one--the cloned bitmaps aren't being manually disposed of and I'm not sure where to, at this point).
Where is the InvalidOperationException in System.Drawing, which causes a red cross to be drawn to the PictureBox coming from, what am I doing wrong in terms of locking and access, and how can I avoid/bypass this error?
I am trying to bypass it with the catch exception and continue logic in the thread, and that I have confirmed works . . . sometimes. At other times, the failed draw attempt seems to complete too far and draws the red cross anyway, and after that point, the PictureBox is thoroughly unresponsive and new frames cannot be drawn to it, even when the video is still running fine.
Perhaps there is a way to refresh the PictureBox so that it accepts new frames?
I was having a problem with the red cross, then I find this and it help me, I hope it helps you too:
WinForms controls and the red X
I'm new to Windows Forms, in my project, i need to change the image in the picture box at runtime. I'm able to do that with the help of a timer. The picture just gets changed. Is it possible to do some transitions when image changes, for example fade in, fade out, blur etc.. If possible could some one please let me know how to do it. I searched in net but in vain.Thanks in advance.
Varun
Simply take new code file and paste below code in it
an original answer for the similar question, answer taken from another question
Answer
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
public class BlendPanel : Panel
{
private Image mImg1;
private Image mImg2;
private float mBlend;
public BlendPanel()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
public Image Image1
{
get { return mImg1; }
set { mImg1 = value; Invalidate(); }
}
public Image Image2
{
get { return mImg2; }
set { mImg2 = value; Invalidate(); }
}
public float Blend
{
get { return mBlend; }
set { mBlend = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
if (mImg1 == null || mImg2 == null)
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), new Rectangle(0, 0, this.Width, this.Height));
else
{
Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
ColorMatrix cm = new ColorMatrix();
ImageAttributes ia = new ImageAttributes();
cm.Matrix33 = mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg2, rc, 0, 0, mImg2.Width, mImg2.Height, GraphicsUnit.Pixel, ia);
cm.Matrix33 = 1F - mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg1, rc, 0, 0, mImg1.Width, mImg1.Height, GraphicsUnit.Pixel, ia);
}
base.OnPaint(e);
}
}
Build your project. You can now drop a BlendPanel from the top of the toolbox onto your form. Here's a sample program that uses it:
private float mBlend;
private int mDir = 1;
public int count = 0;
public Bitmap[] pictures;
public void myPhoto()
{
pictures = new Bitmap[9];
pictures[0] = new Bitmap(#"Library Images\cf3.jpg");
pictures[1] = new Bitmap(#"Library Images\cf4.jpg");
pictures[2] = new Bitmap(#"Library Images\l1.JPG");
pictures[3] = new Bitmap(#"Library Images\l2.JPG");
pictures[4] = new Bitmap(#"Library Images\l3.JPG");
pictures[5] = new Bitmap(#"Library Images\l4.JPG");
pictures[6] = new Bitmap(#"Library Images\l5.JPG");
pictures[7] = new Bitmap(#"Library Images\l6.JPG");
pictures[8] = new Bitmap(#"Library Images\l7.JPG");
timer1.Interval = 50; //time of transition
timer1.Tick += BlendTick;
try
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[++count];
}
catch
{
}
timer1.Enabled = true;
}
private void BlendTick(object sender, EventArgs e)
{
mBlend += mDir * 0.02F;
if (mBlend > 1)
{
mBlend = 0.0F;
if ((count + 1) < pictures.Length)
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[++count];
}
else
{
blendPanel1.Image1 = pictures[count];
blendPanel1.Image2 = pictures[0];
count = 0;
}
}
blendPanel1.Blend = mBlend;
}
You'll need to modify the new Bitmap(#"yourimagePath"); calls. Build and run. You should see the displayed image smoothly morph from your first image to your second image without any flickering.
I hope it helps for other...
There is no built-in support for such effects, but you can implement them. I'd suggest to write a custom control that renders the image and have a method for fade-swap, fade itself can be reached with alpha-blending drawing with .NET Graphics class.
However, Graphics class isn't very fast, I don't recommend to use this technique for big images. If you need some fancy UI with hw-accelerated effects, take a look at WPF.
Blend effects are easy to get going by using the ColorMatrix class. There's a good example available in my answer in this thread.
A simple way to get a blur is to resize the image, making it smaller, then redraw it back, making it larger. The Graphics.InterpolationMode property affects the type of blur you'll get.
Those are quicky do-it-yourself solutions. Any decent graphics library has these kind of operations built-in. You probably want something free, check out ImageMagick.NET
To put it simply, not without external (3rd-party) libraries.