3rd person

Irrlicht.Net is no longer developed or supported, Irrlicht.Net Cross Platform is a much more complete wrapper. Please ask your C# related questions on their forums first.
Locked
jurisekvendov
Posts: 7
Joined: Wed Apr 12, 2006 10:26 pm

3rd person

Post by jurisekvendov »

Hello Irrlicht Users

Thank you for message, but i need a small application with sourcecode made in c# showing 3rd person on a terrain in action. IS THAT POSSIBLE

Hope that you can help me

Please Confirm
Juri Sekvendov
Cube3
Posts: 30
Joined: Wed Mar 15, 2006 7:42 pm
Location: http://cube3.helpmy.net

Post by Cube3 »

http://irrlicht.sourceforge.net/phpBB2/ ... php?t=1140

shouldn't be too hard to port to C# for you.
Platform 3D Engine using Irrlicht.NET
http://cube3.helpmy.net
Cube3
Posts: 30
Joined: Wed Mar 15, 2006 7:42 pm
Location: http://cube3.helpmy.net

Post by Cube3 »

This is a 3rd person camera I partially translated from the C++ C3rdPersonCamera somwehre in the forum. This is by no means perfect... It does not contain camera physics for Rough Terrains for example and I left out some functions. The camera gets its keyboad events from a custom keyboard listener instead of Irrlicht event receiver... If you improve this camera code please post it back to the forum.


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Diagnostics;
using Irrlicht.Scene;
using Irrlicht.Core;

namespace Irrlicht.Framework.Managers
{
public abstract class ICameraSystem
{
public abstract void RefreshCamera();
public ICameraSceneNode Node;
public IrrlichtDevice Device;
public ICameraSystem(IrrlichtDevice device)
{
Device = device;
}

private float _angleY;

/// <summary>
/// Gets or sets the angle Y.
/// </summary>
/// <value>The angle Y.</value>
[XmlAttribute]
public float AngleY
{
get { return _angleY; }
set { _angleY = value; }
}

[XmlIgnore]
public int Direction
{
get
{
if ((_angleY <= 90 - 45) || (_angleY >= 360 - 45))
return 1;
else if (_angleY <= 180 - 45)
return 2;
else if (_angleY <= 270 - 45)
return 3;
else return 4;
}
}
}

public class ThirdPersonCamera : ICameraSystem
{
#region Enumerations

enum EPLAYER_ACTION : int
{
EPA_MOVE_FORWARD = Keys.Up,
EPA_MOVE_BACKWARD = Keys.Down,
EPA_MOVE_LEFT = Keys.Left,
EPA_MOVE_RIGHT = Keys.Right
}

/// <summary>
/// Define player states.
/// </summary>
enum EPLAYER_STATE
{
/// <summary>
/// Player is running.
/// </summary>
EPS_RUNNING,
/// <summary>
/// Player is standing.
/// </summary>
EPS_STANDING
}

#endregion

public int KeyZoomIn = (int)Keys.Home;
public int KeyZoomOut = (int)Keys.End;

#region Player Fields and Properties

private const float EPSILON = 0.0001f;

private float _angleZ;

/// <summary>
/// Gets or sets the angle Z.
/// </summary>
/// <value>The angle Z.</value>
[XmlAttribute]
public float AngleZ
{
get { return _angleZ; }
set { _angleZ = value; }
}

private bool _isActive;

/// <summary>
/// Gets or sets a value indicating whether this instance is active.
/// </summary>
/// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
[XmlAttribute]
public bool IsActive
{
get { return _isActive; }
set { _isActive = value; }
}

private IAnimatedMeshSceneNode _player;

/// <summary>
/// Gets or sets the player.
/// </summary>
/// <value>The player.</value>
[XmlIgnore()]
public IAnimatedMeshSceneNode Player
{
get { return _player; }
set
{
_player = value; _targetOffset = _player.BoundingBox.MaxEdge;
}
}

private Vector3D _targetOffset;
private float _minDist = 50f;
private float _maxDist = 1000.0f;
private float _minAngle = -89.0f;
private float _maxAngle = 70.0f;
private float _zoomSpeed = 2.0f;
private float _dist= 100f;

#endregion

#region Camera Fields and Properties

private float _moveSpeed = 0.1f;
private int _prevTime;
private EPLAYER_STATE _state;

#endregion

public ThirdPersonCamera(IrrlichtDevice device) : base(device)
{
Node = device.SceneManager.AddCameraSceneNodeFPS();
Node.InputReceiverEnabled = false;
}

private void AnimatePlayer(int timeMs)
{
// first loop
if (_prevTime == -1)
{
_prevTime = timeMs;
}

// Timer operations
float timeMsFloat = timeMs - _prevTime;
_prevTime = timeMs;

if (((KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_FORWARD] && !KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_BACKWARD]) || (!KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_FORWARD] && KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_BACKWARD])) ||
((KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_LEFT] && !KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_RIGHT]) || (!KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_LEFT] && KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_RIGHT]))
&& ((KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_LEFT] && KeyBoard.KeyState[(int)Keys.ShiftKey]))
&& ((KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_RIGHT] && KeyBoard.KeyState[(int)Keys.ShiftKey])))
{
if (_state != EPLAYER_STATE.EPS_RUNNING)
{
_state = EPLAYER_STATE.EPS_RUNNING;
Player.SetMD2Animation(Irrlicht.Scene.MD2AnimationType.RUN);
Player.AnimationSpeed = 80;
}
}
else
{
if (_state != EPLAYER_STATE.EPS_STANDING)
{
_state = EPLAYER_STATE.EPS_STANDING;
Player.SetMD2Animation(Irrlicht.Scene.MD2AnimationType.STAND);
}
return; // no movement
}

// Create movement directions based on camera orientation
Vector3D forward = Node.Target - Node.Position;
forward.Y = 0.001f;
Vector3D left = forward.CrossProduct(Node.UpVector);
forward = forward.Normalize();
left = left.Normalize();

if (KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_FORWARD])
{
Player.Position = Player.Position + forward * _moveSpeed * timeMsFloat;
Player.Rotation = new Vector3D(EPSILON, 180.0f - AngleY, EPSILON);
}
else if (KeyBoard.KeyState[(int)EPLAYER_ACTION.EPA_MOVE_BACKWARD])
{
Player.Position = Player.Position - forward * _moveSpeed * timeMsFloat;
}
}

private int _prevCameraMs = 0;

private void AnimateCamera(int timeMs)
{
//if (_previouslyStuck > 0.1f)
// return;

if (KeyBoard.KeyState[(int)Keys.PageDown])
{
AngleZ += 1f;
}
if (KeyBoard.KeyState[(int)Keys.PageUp])
{
AngleZ -= 1f;
}

if (KeyBoard.KeyState[(int)Keys.Left])
{
AngleY += 1f;
}
if (KeyBoard.KeyState[(int)Keys.Right])
{
AngleY -= 1f;
}

// So we don't get huge rotation numbers
if (AngleY > 360.0f)
{
AngleY -= 360.0f;
}
if (AngleY < 0.0f)
{
AngleY += 360.0f;
}


// Ensure Vertical Rotation Angle is bounded correctly
if (AngleZ < _minAngle) AngleZ = _minAngle;
else if (AngleZ > _maxAngle) AngleZ = _maxAngle;

Player.Rotation = new Vector3D(0, -(AngleY + 180), 0);

if ((KeyBoard.KeyState[KeyZoomIn] && !KeyBoard.KeyState[KeyZoomOut]) || (!KeyBoard.KeyState[KeyZoomIn] && KeyBoard.KeyState[KeyZoomOut]))
{
if (KeyBoard.KeyState[KeyZoomIn])
{
_dist += _zoomSpeed;
}
else if (KeyBoard.KeyState[KeyZoomOut])
{
_dist -= _zoomSpeed;
}
// Ensure Distance is bounded correctly
if (_dist < _minDist) _dist = _minDist;
else if (_dist > _maxDist) _dist = _maxDist;
}

// transition between targets.
Vector3D translation = new Vector3D(_dist, 0, 0);
translation.RotateXYBy(-AngleZ, new Vector3D(0,0,0));
translation.RotateXZBy(AngleY, new Vector3D(0,0,0));

Node.Target = Player.Position + _targetOffset;
Node.Position = Player.Position + translation+ _targetOffset;

}

private void animateNode(int timeMs)
{
AnimatePlayer(timeMs);
AnimateCamera(timeMs);
}

public override void RefreshCamera()
{
animateNode(Environment.TickCount);
}
}
}

using System;
using System.Collections.Generic;
using System.Text;

namespace Irrlicht.Framework
{
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;

public class KeyBoard
{
public static bool[] KeyState;

static KeyBoard()
{
// Watch for keyboard activity
KeyboardListener.s_KeyEventHandler += new EventHandler(KeyboardListener_s_KeyEventHandler);
KeyState = new bool[256];
}

public static void Attach()
{
KeyboardListener.Detach();
KeyboardListener.s_KeyEventHandler += new EventHandler(KeyboardListener_s_KeyEventHandler);
}

public static void Detach()
{
KeyboardListener.Detach();
KeyState = new bool[256];
}

public static event KeyPressEventHandler OnKeyChanged;

static void KeyboardListener_s_KeyEventHandler(object sender, EventArgs e)
{
KeyboardListener.UniversalKeyEventArgs eventArgs = (KeyboardListener.UniversalKeyEventArgs)e;
if (eventArgs.m_Msg == 256)
{
KeyBoard.KeyState[eventArgs.m_Key] = true;
OnKeyChanged(null, null);
}
else
{
KeyBoard.KeyState[eventArgs.m_Key] = false;
OnKeyChanged(null, null);
}
}

}


/// <summary>
/// The KeyboardListener is a static class that allows registering a number
/// of event handlers that you want to get called in case some keyboard key is pressed
/// or released. The nice thing is that this KeyboardListener is also active in case
/// the parent application is running in the back.
/// </summary>
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "SkipVerification")]
public class KeyboardListener
{
#region Private declarations

/// <summary>
/// The Window that intercepts Keyboard messages
/// </summary>
private static ListeningWindow s_Listener;

#endregion

#region Private methods
/// <summary>
/// The function that will handle all keyboard activity signaled by the ListeningWindow.
/// In this context handling means calling all registered subscribers for every key pressed / released.
/// </summary>
/// <remarks>
/// Inside this method the events could also be fired by calling
/// s_KeyEventHandler(null,new KeyEventArgs(key,msg)) However, in case one of the registered
/// subscribers throws an exception, execution of the non-executed subscribers is cancelled.
/// </remarks>
/// <param name="key"></param>
/// <param name="msg"></param>
private static void KeyHandler(ushort key, uint msg)
{
if (s_KeyEventHandler != null)
{
Delegate[] delegates = s_KeyEventHandler.GetInvocationList();

foreach (Delegate del in delegates)
{
EventHandler sink = (EventHandler)del;

try
{
// This is a static class, therefore null is passed as the object reference
sink(null, new UniversalKeyEventArgs(key, msg));
}


// You can add some meaningful code to this catch block.
catch { };
}
}
}
#endregion

#region Public declarations

/// <summary>
/// An instance of this class is passed when Keyboard events are fired by the KeyboardListener.
/// </summary>
public class UniversalKeyEventArgs : KeyEventArgs
{
public readonly uint m_Msg;
public readonly ushort m_Key;

public UniversalKeyEventArgs(ushort aKey, uint aMsg)
: base((Keys)aKey)
{
m_Msg = aMsg;
m_Key = aKey;
}
}

/// <summary>
/// For every application thread that is interested in keyboard events
/// an EventHandler can be added to this variable
/// </summary>
public static event EventHandler s_KeyEventHandler;

public static void Detach()
{
s_KeyEventHandler = null;
}


#endregion

#region Public methods

static KeyboardListener()
{
ListeningWindow.KeyDelegate aKeyDelegate = new ListeningWindow.KeyDelegate(KeyHandler);
s_Listener = new ListeningWindow(aKeyDelegate);
}

#endregion

#region Definition ListeningWindow class
/// <summary>
/// A ListeningWindow object is a Window that intercepts Keyboard events.
/// </summary>
private class ListeningWindow : NativeWindow
{
#region Declarations
public delegate void KeyDelegate(ushort key, uint msg);

private const int
WS_CLIPCHILDREN = 0x02000000,
WM_INPUT = 0x00FF,
RIDEV_INPUTSINK = 0x00000100,
RID_INPUT = 0x10000003,
RIM_TYPEKEYBOARD = 1;

private uint m_PrevMessage = 0;
private ushort m_PrevControlKey = 0;
private KeyDelegate m_KeyHandler = null;
#endregion

#region Unsafe types
internal unsafe struct RAWINPUTDEV
{
public ushort usUsagePage;
public ushort usUsage;
public uint dwFlags;
public void* hwndTarget;
};

internal unsafe struct RAWINPUTHEADER
{
public uint dwType;
public uint dwSize;
public void* hDevice;
public void* wParam;
};

internal unsafe struct RAWINPUTHKEYBOARD
{
public RAWINPUTHEADER header;
public ushort MakeCode;
public ushort Flags;
public ushort Reserved;
public ushort VKey;
public uint Message;
public uint ExtraInformation;

};
#endregion

public ListeningWindow(KeyDelegate keyHandlerFunction)
{
m_KeyHandler = keyHandlerFunction;

CreateParams cp = new CreateParams();

// Fill in the CreateParams details.
cp.Caption = "Hidden window";
cp.ClassName = null;
cp.X = 0x7FFFFFFF;
cp.Y = 0x7FFFFFFF;
cp.Height = 0;
cp.Width = 0;
//cp.Parent = parent.Handle;
cp.Style = WS_CLIPCHILDREN;

// Create the actual invisible window
this.CreateHandle(cp);

// Register for Keyboard notification
unsafe
{
try
{
RAWINPUTDEV myRawDevice = new RAWINPUTDEV();
myRawDevice.usUsagePage = 0x01;
myRawDevice.usUsage = 0x06;
myRawDevice.dwFlags = RIDEV_INPUTSINK;
myRawDevice.hwndTarget = this.Handle.ToPointer();

if (RegisterRawInputDevices(&myRawDevice, 1, (uint)sizeof(RAWINPUTDEV)) == false)
{
int err = Marshal.GetLastWin32Error();
throw new Win32Exception(err, "ListeningWindow::RegisterRawInputDevices");
}
}

catch { throw; }
}
}


#region Private methods
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_INPUT:
{
try
{
unsafe
{
uint dwSize, receivedBytes;
uint sizeof_RAWINPUTHEADER = (uint)(sizeof(RAWINPUTHEADER));

// Find out the size of the buffer we have to provide
int res = GetRawInputData(m.LParam.ToPointer(), RID_INPUT, null, &dwSize, sizeof_RAWINPUTHEADER);

if (res == 0)
{
// Allocate a buffer and ...
byte* lpb = stackalloc byte[(int)dwSize];

// ... get the data
receivedBytes = (uint)GetRawInputData((RAWINPUTHKEYBOARD*)(m.LParam.ToPointer()), RID_INPUT, lpb, &dwSize, sizeof_RAWINPUTHEADER);
if (receivedBytes == dwSize)
{
RAWINPUTHKEYBOARD* keybData = (RAWINPUTHKEYBOARD*)lpb;

// Finally, analyze the data
if (keybData->header.dwType == RIM_TYPEKEYBOARD)
{
if ((m_PrevControlKey != keybData->VKey) || (m_PrevMessage != keybData->Message))
{
m_PrevControlKey = keybData->VKey;
m_PrevMessage = keybData->Message;

// Call the delegate in case data satisfies
m_KeyHandler(keybData->VKey, keybData->Message);
}
}
}
else
{
string errMsg = string.Format("WndProc::GetRawInputData (2) received {0} bytes while expected {1} bytes", receivedBytes, dwSize);
throw new Exception(errMsg);
}
}
else
{
string errMsg = string.Format("WndProc::GetRawInputData (1) returned non zero value ({0})", res);
throw new Exception(errMsg);
}
}
}

catch { throw; }
}
break;
}

// In case you forget this you will run into problems
base.WndProc(ref m);
}

#endregion

#region Private external methods

// In case you want to have a comprehensive overview of calling conventions follow the next link:
// http://www.codeproject.com/cpp/calling_ ... tified.asp

[DllImport("User32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool RegisterRawInputDevices(RAWINPUTDEV* rawInputDevices, uint numDevices, uint size);

[DllImport("User32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.I4)]
internal static extern unsafe int GetRawInputData(void* hRawInput,
uint uiCommand,
byte* pData,
uint* pcbSize,
uint cbSizeHeader
);

#endregion
}
#endregion
}
}
Platform 3D Engine using Irrlicht.NET
http://cube3.helpmy.net
Locked