Created
March 1, 2010 19:38
-
-
Save ousttrue/318726 to your computer and use it in GitHub Desktop.
irrlicht tps camera & joy pad test.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <irrlicht.h> | |
#define _USE_MATH_DEFINES | |
#include <math.h> | |
#include <iostream> | |
#include <cassert> | |
#define MEDIA_PATH "E:/vc/irrlicht-1.7.1/media/" | |
using namespace irr; | |
const static f32 MAX_PITCH=88.0f; | |
inline f64 toRadian(f64 deglee) | |
{ | |
return M_PI * deglee / 180.0; | |
} | |
inline f64 toDeglee(f64 radian) | |
{ | |
return 180.0 * radian / M_PI; | |
} | |
enum ID_PICK_TYPE | |
{ | |
// I use this ISceneNode ID to indicate a scene node that is | |
// not pickable by getSceneNodeAndCollisionPointFromRay() | |
ID_IsNotPickable = 0, | |
// I use this flag in ISceneNode IDs to indicate that the | |
// scene node can be picked by ray selection. | |
IDFlag_IsPickable = 1 << 0, | |
// I use this flag in ISceneNode IDs to indicate that the | |
// scene node can be highlighted. In this example, the | |
// homonids can be highlighted, but the level mesh can't. | |
IDFlag_IsHighlightable = 1 << 1 | |
}; | |
namespace irr { | |
class TPSController : public IReferenceCounted | |
{ | |
scene::ISceneNode *person_; | |
core::vector3df centerOffset_; | |
scene::IAnimatedMeshSceneNode *animation_; | |
// 移動距離/msec | |
f32 velocity_; | |
// 移動予定 | |
core::vector3df move_; | |
// personの向き | |
f32 personHead_; | |
// 回転速度/msec | |
f32 personRotationSpeed_; | |
f32 baseAngle_; | |
f32 joystickMoveSpeed_; | |
enum STATUS{ | |
STATUS_STOP, | |
STATUS_WALK, | |
STATUS_JUMP, | |
STATUS_FALL, | |
STATUS_DASH, | |
}; | |
STATUS currentStatus_; | |
STATUS lastStatus_; | |
f32 jumpMove_; | |
f32 jumpPower_; | |
f32 jumpGravity_; | |
f32 lastPersonY_; | |
scene::ICameraSceneNode *camera_; | |
// camera向き | |
f32 head_; | |
f32 pitch_; | |
// personとカメラの距離 | |
f32 distance_; | |
// mouseでの回転速度係数 | |
f32 mouseRotatinSpeed_; | |
// joystickの遊び値 | |
s16 joystickDeadzone_; | |
f32 joystickRotationSpeed_; | |
public: | |
TPSController() | |
: person_(0), animation_(0), velocity_(0.1f), baseAngle_(0), | |
personHead_(0), personRotationSpeed_(8.0f), joystickMoveSpeed_(0.5f), | |
currentStatus_(STATUS_STOP), lastStatus_(STATUS_STOP), | |
jumpMove_(0), jumpPower_(10.0f), jumpGravity_(-0.4f), lastPersonY_(0), | |
camera_(0), head_(0), pitch_(-30.0f), distance_(10.0f), | |
mouseRotatinSpeed_(0.5f), joystickDeadzone_(3200), | |
joystickRotationSpeed_(2.0f) | |
{ | |
//grab(); | |
} | |
~TPSController() | |
{ | |
if(person_) | |
person_->drop(); | |
if(animation_) | |
animation_->drop(); | |
if(camera_) | |
camera_->drop(); | |
} | |
void setPerson(scene::ISceneNode *node, const core::vector3df &offset){ | |
person_=node; | |
person_->grab(); | |
centerOffset_=offset; | |
} | |
void setAnimationNode(scene::IAnimatedMeshSceneNode *animation) | |
{ | |
animation_=animation; | |
animation_->grab(); | |
} | |
void setCamera(scene::ICameraSceneNode *camera){ | |
camera_=camera; | |
camera_->grab(); | |
} | |
void setVelocity(f32 velocity) | |
{ | |
velocity_=velocity; | |
} | |
void setDistance(f32 distance) | |
{ | |
distance_=distance; | |
} | |
// キャラクタがこちら向きになる角度 | |
void setBaseAngle(f32 angle) | |
{ | |
baseAngle_=angle; | |
} | |
void jump() | |
{ | |
if(currentStatus_==STATUS_JUMP){ | |
return; | |
} | |
if(currentStatus_==STATUS_FALL){ | |
return; | |
} | |
currentStatus_=STATUS_JUMP; | |
jumpMove_=jumpPower_; | |
} | |
void moveJoystick(f32 xAxis, f32 yAxis) | |
{ | |
bool update=false; | |
if(xAxis<joystickDeadzone_ && xAxis>-joystickDeadzone_){ | |
xAxis=0; | |
} | |
else{ | |
update=true; | |
} | |
if(yAxis<joystickDeadzone_ && yAxis>-joystickDeadzone_){ | |
yAxis=0; | |
} | |
else{ | |
update=true; | |
} | |
if(update){ | |
move(xAxis/32767.0f*joystickMoveSpeed_, | |
yAxis/32767.0f*joystickMoveSpeed_); | |
} | |
} | |
void rotateJoystick(f32 xAxis, f32 yAxis) | |
{ | |
bool update=false; | |
if(xAxis<joystickDeadzone_ && xAxis>-joystickDeadzone_){ | |
xAxis=0; | |
} | |
else{ | |
update=true; | |
} | |
if(yAxis<joystickDeadzone_ && yAxis>-joystickDeadzone_){ | |
yAxis=0; | |
} | |
else{ | |
update=true; | |
} | |
if(update){ | |
rotate( | |
xAxis/32767.0f*joystickRotationSpeed_, | |
yAxis/32767.0f*joystickRotationSpeed_); | |
} | |
} | |
// キャラクターの移動(左スティック) | |
// カメラ方向を基準とする前後左右に移動する | |
void move(f32 xMove, f32 zMove) | |
{ | |
if(!person_){ | |
return; | |
} | |
if(!camera_){ | |
return; | |
} | |
if(xMove==0 && zMove==0){ | |
if(currentStatus_!=STATUS_JUMP && currentStatus_!=STATUS_FALL){ | |
currentStatus_=STATUS_STOP; | |
} | |
return; | |
} | |
if(currentStatus_!=STATUS_JUMP && currentStatus_!=STATUS_FALL){ | |
currentStatus_=STATUS_WALK; | |
} | |
core::vector3df cameraPosition=camera_->getPosition(); | |
core::vector3df cameraTarget=camera_->getTarget(); | |
// カメラの向きに垂直な左方向を計算する | |
core::vector3df zAxis=cameraTarget-cameraPosition; | |
zAxis.Y=0; | |
zAxis.normalize(); | |
core::vector3df xAxis=core::vector3df(0, 1, 0).crossProduct(zAxis); | |
// 移動ベクトル | |
move_=zAxis*zMove+xAxis*xMove; | |
//move_.normalize(); | |
// 向き | |
f32 angle=static_cast<f32>(toDeglee(atan2(move_.X, move_.Z))); | |
f32 rotation=angle-personHead_; | |
if(rotation!=0){ | |
while(rotation<-180.0f){ | |
rotation+=360.0f; | |
} | |
while(rotation>180.0f){ | |
rotation-=360.0f; | |
} | |
if(rotation>0){ | |
if(rotation<=personRotationSpeed_){ | |
personHead_=angle; | |
} | |
else{ | |
personHead_+=personRotationSpeed_; | |
} | |
} | |
else if(rotation<0){ | |
if(rotation>=-personRotationSpeed_){ | |
personHead_=angle; | |
} | |
else{ | |
personHead_-=personRotationSpeed_; | |
} | |
} | |
} | |
} | |
// 視点の回転(マウス) | |
void rotateMouse(s32 head, s32 pitch) | |
{ | |
rotate(head*mouseRotatinSpeed_, pitch*mouseRotatinSpeed_); | |
} | |
// 視点の回転 | |
void rotate(f32 head, f32 pitch) | |
{ | |
if(!person_){ | |
return; | |
} | |
if(!camera_){ | |
return; | |
} | |
head_+=head; | |
while(head_<-180.0f){ | |
head_+=360.0f; | |
} | |
while(head_>180.0f){ | |
head_-=360.0f; | |
} | |
pitch_+=pitch; | |
if(pitch_<-MAX_PITCH){ | |
pitch_=-MAX_PITCH; | |
} | |
else if(pitch_>MAX_PITCH){ | |
pitch_=MAX_PITCH; | |
} | |
} | |
// 移動を反映する | |
void update(u32 milisec) | |
{ | |
if(!person_){ | |
return; | |
} | |
core::vector3df personPosition=person_->getPosition(); | |
// person jump | |
if(currentStatus_==STATUS_JUMP){ | |
jumpMove_+=jumpGravity_; | |
if(jumpMove_<0){ | |
currentStatus_=STATUS_FALL; | |
} | |
} | |
else if(currentStatus_==STATUS_FALL){ | |
jumpMove_+=jumpGravity_; | |
// 接地判定? | |
if(personPosition.Y>=lastPersonY_){ | |
jumpMove_=0; | |
currentStatus_=STATUS_STOP; | |
} | |
lastPersonY_=personPosition.Y; | |
} | |
// person move | |
person_->setPosition(personPosition+ | |
core::vector3df(0, jumpMove_, 0)+ | |
move_*static_cast<f32>(milisec)*velocity_); | |
move_=core::vector3df(0, 0, 0); | |
// person rotation | |
person_->setRotation( | |
core::vector3df(0, personHead_+baseAngle_, 0)); | |
if(!animation_){ | |
return; | |
} | |
if(currentStatus_==lastStatus_){ | |
return; | |
} | |
switch(currentStatus_) | |
{ | |
case STATUS_STOP: | |
animation_->setMD2Animation(scene::EMAT_STAND); | |
break; | |
case STATUS_WALK: | |
animation_->setMD2Animation(scene::EMAT_RUN); | |
break; | |
} | |
lastStatus_=currentStatus_; | |
} | |
void updateCamera() | |
{ | |
if(!camera_){ | |
return; | |
} | |
f32 ch=static_cast<f32>(cos(toRadian(head_))); | |
f32 sh=static_cast<f32>(sin(toRadian(head_))); | |
f32 cp=static_cast<f32>(cos(toRadian(pitch_))); | |
f32 sp=static_cast<f32>(sin(toRadian(pitch_))); | |
core::vector3df cameraDirection(-sh*cp, -sp, -ch*cp); | |
core::vector3df target=person_->getPosition()+centerOffset_; | |
camera_->setPosition(target+cameraDirection*distance_); | |
camera_->setTarget(target); | |
} | |
}; | |
class MyEventReceiver : public IEventReceiver | |
{ | |
bool KeyIsDown[KEY_KEY_CODES_COUNT]; | |
SEvent::SJoystickEvent JoystickState; | |
public: | |
MyEventReceiver() | |
{ | |
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i){ | |
KeyIsDown[i] = false; | |
} | |
} | |
virtual bool OnEvent(const SEvent& event) | |
{ | |
if (event.EventType == EET_KEY_INPUT_EVENT){ | |
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown; | |
} | |
if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT | |
&& event.JoystickEvent.Joystick == 0) { | |
JoystickState = event.JoystickEvent; | |
} | |
return false; | |
} | |
virtual bool IsKeyDown(EKEY_CODE keyCode) const | |
{ | |
return KeyIsDown[keyCode]; | |
} | |
s16 getJoystickAxis(u32 joystick, u32 axis)const | |
{ | |
if(joystick!=0){ | |
return 0; | |
} | |
return JoystickState.Axis[axis]; | |
} | |
bool IsButtonPressed(u32 joystick, u32 button)const | |
{ | |
if(joystick!=0){ | |
return false; | |
} | |
return JoystickState.IsButtonPressed(button); | |
} | |
}; | |
namespace scene { | |
class TPSAnimator : public ISceneNodeAnimator | |
{ | |
TPSController *controller_; | |
u32 lastMS; | |
public: | |
TPSAnimator(TPSController *controller) | |
: lastMS(0), controller_(controller) | |
{} | |
//! Destructor | |
virtual ~TPSAnimator() {} | |
//! Animates a scene node. | |
virtual void animateNode(ISceneNode* node, u32 timeMs){ | |
u32 interval=timeMs-lastMS; | |
lastMS=timeMs; | |
controller_->update(interval); | |
} | |
//! Creates a clone of this animator. | |
virtual ISceneNodeAnimator* createClone( | |
ISceneNode* node, ISceneManager* newManager=0){ | |
return 0; | |
} | |
//! Returns true if this animator receives events. | |
virtual bool isEventReceiverEnabled() const | |
{ | |
return false; | |
} | |
//! Event receiver, | |
//! override this function for camera controlling animators | |
virtual bool OnEvent(const SEvent& event) | |
{ | |
return true; | |
} | |
//! Returns type of the scene node animator | |
virtual ESCENE_NODE_ANIMATOR_TYPE getType() const | |
{ | |
return ESNAT_UNKNOWN; | |
} | |
}; | |
} | |
} | |
int main() | |
{ | |
// create device | |
MyEventReceiver receiver; | |
IrrlichtDevice* device = createDevice(video::EDT_OPENGL, | |
core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver); | |
if (device == 0){ | |
return 1; // could not create selected driver. | |
} | |
video::IVideoDriver* driver = device->getVideoDriver(); | |
scene::ISceneManager* smgr = device->getSceneManager(); | |
// map | |
device->getFileSystem()->addZipFileArchive(MEDIA_PATH "map-20kdm2.pk3"); | |
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); | |
scene::IMeshSceneNode* q3node = 0; | |
q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0), 0, IDFlag_IsPickable); | |
q3node->setPosition(core::vector3df(-1350,-130,-1400)); | |
scene::ITriangleSelector* selector = smgr->createOctreeTriangleSelector( | |
q3node->getMesh(), q3node, 128); | |
q3node->setTriangleSelector(selector); | |
selector->drop(); | |
const f32 scalingFactor=1.2f; | |
/* | |
// ninja | |
scene::IAnimatedMesh *ninjaMesh=smgr->getMesh(MEDIA_PATH "ninja.b3d"); | |
scene::ISceneNode *ninjaNode=smgr->addEmptySceneNode(); | |
scene::IAnimatedMeshSceneNode *ninja = | |
smgr->addAnimatedMeshSceneNode(ninjaMesh, ninjaNode); | |
assert(ninja); | |
ninja->setMaterialFlag(video::EMF_LIGHTING, false); | |
//ninja->setFrameLoop(0, 13); | |
ninja->setAnimationSpeed(15); | |
ninja->setScale(core::vector3df(scalingFactor)); | |
*/ | |
scene::IAnimatedMesh *SydneyMesh = smgr->getMesh(MEDIA_PATH "sydney.md2"); | |
scene::IAnimatedMeshSceneNode *sydney = | |
smgr->addAnimatedMeshSceneNode( SydneyMesh ); | |
sydney->setMaterialTexture(0, | |
driver->getTexture(MEDIA_PATH "sydney.bmp") ); | |
sydney->setMaterialFlag(video::EMF_LIGHTING, false); | |
sydney->setMD2Animation(scene::EMAT_STAND); | |
sydney->setScale(core::vector3df(scalingFactor)); | |
// camera | |
scene::ICameraSceneNode *camera=smgr->addCameraSceneNode(); | |
// TPS control | |
TPSController *controller=new TPSController; | |
// TPS control animator | |
{ | |
scene::ISceneNodeAnimator* anim = new scene::TPSAnimator(controller); | |
sydney->addAnimator(anim); | |
anim->drop(); | |
} | |
{ | |
// collision animator | |
const core::aabbox3df& box=sydney->getBoundingBox(); | |
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( | |
selector, sydney, scalingFactor*(box.MaxEdge-box.getCenter()), | |
core::vector3df(0,-10,0), -scalingFactor*(box.getCenter())); | |
sydney->addAnimator(anim); | |
anim->drop(); | |
} | |
// Add a colorful irrlicht logo | |
{ | |
device->getGUIEnvironment()->addImage( | |
driver->getTexture(MEDIA_PATH "irrlichtlogoalpha2.tga"), | |
core::position2d<s32>(10,20)); | |
gui::IGUIStaticText* diagnostics = device->getGUIEnvironment()->addStaticText( | |
L"", core::rect<s32>(10, 10, 400, 20)); | |
diagnostics->setOverrideColor(video::SColor(255, 255, 255, 0)); | |
} | |
// controller | |
controller->setPerson(sydney, scalingFactor*core::vector3df(0, 18.0f, 0)); | |
controller->setDistance(scalingFactor*40.0f); | |
controller->setAnimationNode(sydney); | |
controller->setCamera(camera); | |
controller->setBaseAngle(-90.0f); | |
controller->setVelocity(0.5f*scalingFactor); | |
// activate joysticks | |
core::array<SJoystickInfo> joystickInfo; | |
device->activateJoysticks(joystickInfo); | |
gui::ICursorControl *cursor=device->getCursorControl(); | |
cursor->setVisible(false); | |
core::vector2di lastMouse=cursor->getPosition(); | |
int lastFPS = -1; | |
u32 then = device->getTimer()->getTime(); | |
const f32 MOVEMENT_SPEED = 5.f; | |
while(device->run()) | |
{ | |
// update | |
const u32 now = device->getTimer()->getTime(); | |
const u32 frameDeltaTime = now - then; | |
then = now; | |
if(receiver.IsKeyDown(KEY_ESCAPE)){ | |
device->closeDevice(); | |
break; | |
} | |
//////////////////////////////////////////////////////////// | |
// keyboard | |
//////////////////////////////////////////////////////////// | |
// w | |
// asd move | |
f32 zMove=0; | |
f32 xMove=0; | |
if(receiver.IsKeyDown(KEY_KEY_W)){ | |
zMove=1.0f; | |
} | |
else if(receiver.IsKeyDown(KEY_KEY_S)){ | |
zMove=-1.0f; | |
} | |
if(receiver.IsKeyDown(KEY_KEY_A)){ | |
xMove=-1.0f; | |
} | |
else if(receiver.IsKeyDown(KEY_KEY_D)){ | |
xMove=1.0f; | |
} | |
controller->move(xMove, zMove); | |
// jump | |
if(receiver.IsKeyDown(KEY_SPACE)){ | |
controller->jump(); | |
} | |
// rotattion | |
f32 head=0; | |
f32 pitch=0; | |
if(receiver.IsKeyDown(KEY_LEFT)){ | |
head=-1.0f; | |
} | |
else if(receiver.IsKeyDown(KEY_RIGHT)){ | |
head=1.0f; | |
} | |
if(receiver.IsKeyDown(KEY_DOWN)){ | |
pitch=-1.0f; | |
} | |
else if(receiver.IsKeyDown(KEY_UP)){ | |
pitch=1.0f; | |
} | |
controller->rotate(head, pitch); | |
//////////////////////////////////////////////////////////// | |
// mouse | |
//////////////////////////////////////////////////////////// | |
// mouse rotation | |
core::vector2di mouse=cursor->getPosition(); | |
controller->rotateMouse(mouse.X-lastMouse.X, lastMouse.Y-mouse.Y); | |
cursor->setPosition(0.5f, 0.5f); | |
lastMouse=cursor->getPosition(); | |
//////////////////////////////////////////////////////////// | |
// joy pad | |
//////////////////////////////////////////////////////////// | |
// left analog stick | |
controller->moveJoystick( | |
static_cast<f32>( | |
receiver.getJoystickAxis(0, SEvent::SJoystickEvent::AXIS_X)), | |
static_cast<f32>( | |
-receiver.getJoystickAxis(0, SEvent::SJoystickEvent::AXIS_Y))); | |
// right analog stick | |
controller->rotateJoystick( | |
static_cast<f32>( | |
receiver.getJoystickAxis(0, SEvent::SJoystickEvent::AXIS_R)), | |
static_cast<f32>( | |
-receiver.getJoystickAxis(0, SEvent::SJoystickEvent::AXIS_Z))); | |
// pad jump | |
if(receiver.IsButtonPressed(0, 0)){ | |
controller->jump(); | |
} | |
//controller->update(frameDeltaTime); | |
controller->updateCamera(); | |
// draw | |
driver->beginScene(true, true, video::SColor(255,113,113,133)); | |
smgr->drawAll(); | |
device->getGUIEnvironment()->drawAll(); | |
driver->endScene(); | |
// fps | |
int fps = driver->getFPS(); | |
if (lastFPS != fps) | |
{ | |
core::stringw tmp(L"Movement Example - Irrlicht Engine ["); | |
tmp += driver->getName(); | |
tmp += L"] fps: "; | |
tmp += fps; | |
device->setWindowCaption(tmp.c_str()); | |
lastFPS = fps; | |
} | |
} | |
controller->drop(); | |
device->drop(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment