void BasicOpenGLView::mouseMoveEvent(QMouseEvent *event) { float eventX = (float)event->x() / width(); float eventY = 1.0f - (float) event->y() / height(); eventX -= 0.5f; eventY -= 0.5f; eventX *= 2.0f; eventY *= 2.0f; Vector3 curPoint(eventX, eventY); if(mFirstFrameDragging) { mLastMousePos = curPoint; mFirstFrameDragging = false; return; } Vector3 difference; for(size_t i = 0; i < 3; ++i) { difference.elements[i] = curPoint.elements[i] - mLastMousePos.elements[i]; } /** * @todo assignment two * use the mouse input to modify mViewMatrix to work as an arc-ball interface, * or to rotate the viewer in the XZ plane, depending on the selected mode in the * UI (Arc Ball or World crawler) */ Matrix4x4 rotationX = Matrix4x4::RotationX(-difference.elements[1]); Matrix4x4 rotationY = Matrix4x4::RotationY(difference.elements[0]); Vector3 oldForward(mViewMatrix[2], mViewMatrix[6], mViewMatrix[10]); oldForward.normalize(); oldForward *= -mDistance; Matrix4x4 translateToOrigin = Matrix4x4::Translation(oldForward); mViewMatrix = mViewMatrix * translateToOrigin; mViewMatrix = (mViewMatrix * rotationX) * rotationY; Vector3 newForward(mViewMatrix[2], mViewMatrix[6], mViewMatrix[10]); newForward.normalize(); newForward *= mDistance; Matrix4x4 translateFromOrigin = Matrix4x4::Translation(newForward); mViewMatrix = mViewMatrix * translateFromOrigin; mLastMousePos = curPoint; }
void BasicOpenGLView::wheelEvent(QWheelEvent * e) { int delta = e->delta(); Vector3 oldForward(mViewMatrix[2], mViewMatrix[6], mViewMatrix[10]); oldForward.normalize(); oldForward *= -mDistance; Matrix4x4 translateToOrigin = Matrix4x4::Translation(oldForward); mViewMatrix = mViewMatrix * translateToOrigin; mDistance -= ((float)delta) / 10.0f; Vector3 newForward(mViewMatrix[2], mViewMatrix[6], mViewMatrix[10]); newForward.normalize(); newForward *= mDistance; Matrix4x4 translateFromOrigin = Matrix4x4::Translation(newForward); mViewMatrix = mViewMatrix * translateFromOrigin; }
// client / slave code void DynamicActorReplicaComponent::deserialize(RakNet::DeserializeParameters *deserializeParameters) { // a little base class magic SLBaseClass::deserialize(deserializeParameters); RakNet::BitStream& bitStream(deserializeParameters->serializationBitstream[0]); if (bitStream.GetNumberOfBitsUsed()==0) { return; } //Old Way: //bitStream.ReadAlignedBytes( (unsigned char *)&_actorDatagram, sizeof(Dynamic2DActorDatagram) ); Compressed_Dynamic2DActorDatagram comValues; bitStream.ReadAlignedBytes( (unsigned char *)&comValues, sizeof(Compressed_Dynamic2DActorDatagram) ); _actorDatagram._x = comValues._x; _actorDatagram._y = comValues._y; _actorDatagram._fx = TCompressedFixpoint<float,char,8>::readInflate(comValues._fx, -1.0f, 1.0f ); _actorDatagram._fy = TCompressedFixpoint<float,char,8>::readInflate(comValues._fy, -1.0f, 1.0f ); _killCount = _actorDatagram._killCount = comValues._killCount; _actorDatagram._lvx = comValues._lvx; _actorDatagram._lvy = comValues._lvy; _actorDatagram._avz = comValues._avz; _actorDatagram._updateTick = comValues._updateTick; _killCount = _actorDatagram._killCount; if(getActorSprite() == nullptr) { return; } AbstractVehicle* vehicle(getActorSprite()->getVehicle()); if(vehicle != nullptr) { Vec3 serverPosition( _actorDatagram._x, _actorDatagram._y, 0.0f ); Vec3 serverForward( _actorDatagram._fx, _actorDatagram._fy, 0.0f ); Vec3 serverLinearVelocity( _actorDatagram._lvx, _actorDatagram._lvy, 0.0f ); Vec3 serverAngularVelocity( 0.0f, 0.0f, _actorDatagram._avz ); float linearInterpolationFactor(0.95f); Vec3 newPosition(ProtocolUtilities::interpolateNetVector(vehicle->position(), serverPosition, linearInterpolationFactor)); Vec3 newForward(ProtocolUtilities::interpolateNetVector(vehicle->forward(), serverForward, linearInterpolationFactor)); Vec3 newLinearVelocity(ProtocolUtilities::interpolateNetVector(vehicle->linearVelocity(), serverLinearVelocity, linearInterpolationFactor)); Vec3 newAngularVelocity(ProtocolUtilities::interpolateNetVector(vehicle->angularVelocity(), serverAngularVelocity, linearInterpolationFactor)); vehicle->setPosition(newPosition); vehicle->regenerateLocalSpace(newForward, 0.0f); vehicle->setLinearVelocity(newLinearVelocity); vehicle->setAngularVelocity(newAngularVelocity); // very important to notify the vehicle that // it's internal state has been changed from the outside // see PhysicsVehicle::update vehicle->setDirty(); _localSpaceData = vehicle->getLocalSpaceData(); _motionState.readLocalSpaceData(_localSpaceData); } }
hkDemo::Result PlanetGravityDemo::stepDemo() { // Update lighting { // Update the light source to be at the camera float position[3]; m_cameraPosition.store3( position ); m_flashLight->setPosition( position ); // Update the light direction to be pointing toward the character controller rigid body hkVector4 directionVector; directionVector.setSub4( m_cameraPosition, m_characterRigidBody->getPosition() ); directionVector.mul4( -1.0f ); directionVector.normalize3(); float direction[3]; directionVector.store3( direction ); m_flashLight->setDirection( direction ); } // Detach the camera from the character when P is pressed. if( m_env->m_window->getKeyboard().wasKeyPressed('P') ) { m_detachedCamera = !m_detachedCamera; } // Update turrets for( int i = 0; i < m_turrets.getSize(); i++ ) { Turret& turret = m_turrets[i]; turret.cooldown -= m_timestep; // Make the turret spin turret.hinge->setMotorTargetAngle( turret.hinge->getMotorTargetAngle() + ( m_timestep / 5.f ) ); // Bail out if the turret is "hot" if( turret.cooldown > 0.0f ) { continue; } // Generate a curved raycast and shoot the ray // This has to be done every time-step as it's in world-space { const hkReal radius = 14.8f; hkRotation rot; hkVector4 offset; hkVector4 turretDown; rot.set( turret.turretRigidBody->getRotation() ); offset = turret.turretRigidBody->getPosition(); turretDown.setMul4( -1.0f, rot.getColumn(2) ); hkpLinearParametricCurve myCurve; // Move the ray's source a little up so it's coming from the center of the barrel hkTransform localTransform( hkQuaternion::getIdentity(), hkVector4( 0.0f, 0.0f, 0.7f ) ); // Create a curve of 20 points for( int j = 0; j < 20; j++ ) { hkReal angle = HK_REAL_PI * static_cast<hkReal>(j) / 15.0f; hkVector4 newPoint( radius * 2.0f * sin( angle ), 0.0f, radius * 2.0f * cos( angle ) ); newPoint.setTransformedPos( localTransform, newPoint ); newPoint.setTransformedPos( turret.turretRigidBody->getTransform(), newPoint ); newPoint.addMul4( radius * 2.0f, turretDown ); myCurve.addPoint( newPoint ); } // We only need the closest hit (as our lasers can't pass through objects) // so hkpClosestRayHitCollector is used. hkpClosestRayHitCollector raycastOutput; hkReal t = castCurvedRay( raycastOutput, myCurve, 20 ); // Apply a large force to the closest rb we hit, along the tangent at the colliding point if( raycastOutput.hasHit() ) { hkpRigidBody* hitRb = hkGetRigidBody( raycastOutput.getHit().m_rootCollidable ); if( hitRb->getMotionType() != hkpMotion::MOTION_FIXED ) { hkVector4 tangent; myCurve.getTangent( t, tangent ); tangent.mul4( 15000.0f ); applyScaledLinearImpulse( hitRb, tangent ); turret.cooldown = 3.0f; } } } } m_world->markForWrite(); // Update the character context m_characterRigidBody->m_up = m_worldUp; hkReal posX = 0.0f; hkReal posY = 0.0f; if( !m_detachedCamera ) { float deltaAngle; CharacterUtils::getUserInputForCharacter( m_env, deltaAngle, posX, posY ); if( ( ( hkMath::fabs( posX ) < HK_REAL_MAX ) && ( hkMath::fabs( posY ) < HK_REAL_MAX ) ) && ( posX || posY ) ) { // find new orientation in local space hkVector4 newForward( -posY, 0.0f, -posX ); hkVector4 absoluteForward( 1.0f, 0.0f, 0.0f ); hkReal characterAngle = hkMath::acos( absoluteForward.dot3( newForward ) ); // Calculate cross product to get sign of rotation. hkVector4 crossProduct; crossProduct.setCross( absoluteForward, newForward ); if( crossProduct(1) < 0.0f ) { characterAngle *= -1.0f; } // Rotate the character's rigid body to face in the direction it's moving hkRotation newRotation; newRotation.setAxisAngle( m_worldUp, characterAngle ); m_characterForward.setRotatedDir( newRotation, m_cameraForward ); m_characterForward.normalize3(); } // Rotate the camera's forward vector based on world up vector and mouse movement if( deltaAngle != 0.0f && m_characterRigidBody->getRigidBody()->getRotation().hasValidAxis() ) { hkRotation newRotation; newRotation.setAxisAngle( m_worldUp, deltaAngle ); m_cameraForward.setRotatedDir( newRotation, m_cameraForward ); m_cameraForward.normalize3(); } } HK_TIMER_BEGIN( "set character state", HK_NULL ); hkpCharacterInput input; hkpCharacterOutput output; { input.m_atLadder = false; input.m_inputLR = posX; input.m_inputUD = posY; if( m_detachedCamera ) { input.m_wantJump = false; } else { input.m_wantJump = m_env->m_window->getMouse().wasButtonPressed( HKG_MOUSE_LEFT_BUTTON ) || m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_1 ); } // Check that we have a valid rotation. Probably won't for the first couple of frames. if( !( m_characterRigidBody->getRigidBody()->getRotation().hasValidAxis() ) ) { input.m_up = hkVector4( 0.0f, 0.0f, 1.0f ); input.m_forward = m_cameraForward; } else { input.m_up = m_worldUp; // Recalculate m_forward so it's perpendicular to m_worldUp hkVector4 newRot; newRot.setCross( m_cameraForward, m_worldUp ); m_cameraForward.setCross( m_worldUp, newRot ); // Display character's current heading hkRotation characterRotation; characterRotation.set( m_characterRigidBody->getRigidBody()->getRotation() ); HK_DISPLAY_ARROW( m_characterRigidBody->getPosition(), characterRotation.getColumn(0), hkColor::LIMEGREEN ); input.m_forward = m_cameraForward; } hkStepInfo stepInfo; stepInfo.m_deltaTime = m_timestep; stepInfo.m_invDeltaTime = 1.0f / m_timestep; input.m_stepInfo = stepInfo; input.m_characterGravity.setMul4( -20.0f, m_worldUp ); input.m_velocity = m_characterRigidBody->getRigidBody()->getLinearVelocity(); input.m_position = m_characterRigidBody->getRigidBody()->getPosition(); { hkpSurfaceInfo ground; m_characterRigidBody->checkSupport( stepInfo, ground ); // Avoid accidental state changes (Smooth movement on stairs) // During transition supported->unsupported continue to return N-frames hkpSurfaceInfo data from previous supported state { // Number of frames to skip (continue with previous hkpSurfaceInfo data) const int skipFramesInAir = 6; if( input.m_wantJump ) { m_framesInAir = skipFramesInAir; } hkpSurfaceInfo* currInfo; if( ground.m_supportedState != hkpSurfaceInfo::SUPPORTED ) { if( m_framesInAir < skipFramesInAir ) { input.m_isSupported = true; currInfo = m_previousGround; } else { input.m_isSupported = false; currInfo = &ground; } m_framesInAir++; } else { input.m_isSupported = true; currInfo = &ground; m_previousGround->set( ground ); // reset old number of frames if( m_framesInAir > skipFramesInAir ) { m_framesInAir = 0; } } input.m_surfaceNormal = currInfo->m_surfaceNormal; input.m_surfaceVelocity = currInfo->m_surfaceVelocity; input.m_surfaceMotionType = currInfo->m_surfaceMotionType; } } HK_TIMER_END(); } // Apply the character state machine { HK_TIMER_BEGIN( "update character state", HK_NULL ); m_characterContext->update( input, output ); HK_TIMER_END(); } //Apply the player character controller { HK_TIMER_BEGIN( "simulate character", HK_NULL ); // Set output velocity from state machine into character rigid body m_characterRigidBody->setLinearVelocity( output.m_velocity, m_timestep ); HK_TIMER_END(); m_world->unmarkForWrite(); } // Rotate the character { hkRotation newOrientation; newOrientation.getColumn(0) = m_characterForward; newOrientation.getColumn(1) = m_worldUp; newOrientation.getColumn(2).setCross( newOrientation.getColumn(0), newOrientation.getColumn(1) ); newOrientation.renormalize(); reorientCharacter( newOrientation ); } // Step the world hkDefaultPhysicsDemo::stepDemo(); // Display state { hkpCharacterStateType state = m_characterContext->getState(); char* stateStr; switch( state ) { case HK_CHARACTER_ON_GROUND: { stateStr = "On Ground"; break; } case HK_CHARACTER_JUMPING: { stateStr = "Jumping"; break; } case HK_CHARACTER_IN_AIR: { stateStr = "In Air"; break; } default: { stateStr = "Other"; break; } } char buffer[255]; hkString::snprintf( buffer, 255, "State : %s", stateStr ); m_env->m_textDisplay->outputText( buffer, 20.f, 270.f, 0xffffffff ); } // // Handle crouching (only for capsule) // if( !m_detachedCamera ) { m_world->markForWrite(); hkBool wantCrouch = ( m_env->m_window->getMouse().getButtonState() & HKG_MOUSE_RIGHT_BUTTON ) || ( m_env->m_gamePad->getButtonState() & HKG_PAD_BUTTON_2 ); hkBool isCrouching = ( m_characterRigidBody->getRigidBody()->getCollidable()->getShape() == m_crouchShape ); // We want to stand if( isCrouching && !wantCrouch ) { m_characterRigidBody->getRigidBody()->setShape( m_standShape ); } // We want to crouch else if( !isCrouching && wantCrouch ) { m_characterRigidBody->getRigidBody()->setShape( m_crouchShape ); } m_world->unmarkForWrite(); } // Transparent camera handling if( !m_detachedCamera ) { m_world->markForWrite(); handleCamera(); m_world->unmarkForWrite(); } return hkDemo::DEMO_OK; }