////////////////////////////////////////////////////////////////////////// // getDepth BcU32 ScnViewComponent::getDepth( const MaVec3d& WorldPos ) const { MaVec4d ScreenSpace = MaVec4d( WorldPos, 1.0f ) * ViewUniformBlock_.ClipTransform_; BcF32 Depth = 1.0f - BcClamp( ScreenSpace.z() / ScreenSpace.w(), 0.0f, 1.0f ); return BcU32( Depth * BcF32( 0xffffff ) ); }
////////////////////////////////////////////////////////////////////////// // setBehaviourMove void GaGameUnit::setBehaviourMove( const BcFixedVec2d& Target, BcBool IsAttackMove, BcBool DrawDebug ) { if( Health_ > 0.0f ) { Behaviour_ = BEHAVIOUR_MOVE; MoveTargetPosition_ = Target; IsAttackMove_ = IsAttackMove; // Hacky clamp. BcFixed HW = ( 1280.0f * 0.5f ) / 32.0f - 1.0f; BcFixed HH = ( 720.0f * 0.5f ) / 32.0f - 1.0f; MoveTargetPosition_.x( BcClamp( MoveTargetPosition_.x(), -HW, HW ) ); MoveTargetPosition_.y( BcClamp( MoveTargetPosition_.y(), -HH, HH ) ); if( DrawDebug ) { pSimulator_->addDebugPoint( Target, 0.5f, IsAttackMove ? RsColour::RED : RsColour::GREEN ); } } }
////////////////////////////////////////////////////////////////////////// // update //virtual void GaRobotComponent::update( BcF32 Tick ) { if( Health_ <= 0.0f ) { return; } CurrentOpTimer_ -= Tick; if( CurrentOpTimer_ < 0.0f ) { CurrentOpTimer_ += CurrentOpTime_; // Handle robot program. BcBool ExecutedCode = BcFalse; if( Program_.size() > 0 ) { CurrentOp_ = NextOp_; const auto& Op = Program_[ CurrentOp_ ]; if( Op.State_ == CurrentState_ ) { auto Condition = ProgramFunctionMap_[ Op.Condition_ ]; if( Condition != nullptr ) { if( Condition( this, Op.ConditionVar_ ) ) { auto Operation = ProgramFunctionMap_[ Op.Operation_ ]; if( Operation == nullptr ) { BcPrintf( "No operation \"%s\"\n", Op.Operation_.c_str() ); } else { auto RetVal = Operation( this, Op.OperationVar_ ); if( RetVal != BcErrorCode ) { CurrentState_ = RetVal; } } } } ExecutedCode = BcTrue; } // Advance to next valid op. if( ExecutedCode ) { for( BcU32 Idx = 0; Idx < Program_.size(); ++Idx ) { NextOp_ = ( NextOp_ + 1 ) % Program_.size(); if( Program_[ NextOp_ ].State_ == CurrentState_ ) { break; } } } // Did we fail to run code? If so, reset to op 0 and the state of op 0. if( ExecutedCode == BcFalse ) { NextOp_ = 0; CurrentState_ = Program_[ NextOp_ ].State_; } } } // Grab entity + position. auto Entity = getParentEntity(); auto LocalPosition = Entity->getLocalPosition(); // Move if we need to move towards our target position. if( ( TargetPosition_ - LocalPosition ).magnitudeSquared() > ( TargetDistance_ * TargetDistance_ ) ) { if( MoveTimer_ <= 0.0f ) { Velocity_ += ( TargetPosition_ - LocalPosition ).normal() * MaxVelocity_; } } else { BcF32 SlowDownTick = BcClamp( Tick * 50.0f, 0.0f, 1.0f ); Velocity_ -= ( Velocity_ * SlowDownTick ); } // TODO LATER: Do rotation. if( Velocity_.magnitudeSquared() > 0.1f ) { auto Angle = std::atan2( Velocity_.z(), Velocity_.x() ) + BcPIDIV2; MaMat4d RotMat; RotMat.rotation( MaVec3d( 0.0f, Angle, 0.0f ) ); Base_->setLocalMatrix( RotMat ); } // TODO LATER: Do rotation. auto Robots = getRobots( 1 - Team_ ); if( Robots.size() > 0 ) { auto Robot = Robots[ 0 ]; auto RobotPosition = Robot->getParentEntity()->getLocalPosition(); auto VectorTo = RobotPosition - LocalPosition; // Push out of away. if( VectorTo.magnitude() < 3.0f ) { BcF32 Factor = ( 3.0f - VectorTo.magnitude() ) / 3.0f; BcF32 InvFactor = 1.0f - Factor; Velocity_ = ( -( VectorTo.normal() * MaxVelocity_ ) * Factor * 3.0f ) + ( Velocity_ * InvFactor ); } // Face turret. auto Angle = std::atan2( VectorTo.z(), VectorTo.x() ) + BcPIDIV2; MaMat4d RotMat; RotMat.rotation( MaVec3d( 0.0f, Angle, 0.0f ) ); Turret_->setLocalMatrix( RotMat ); } LocalPosition += Velocity_ * Tick; // Slow down velocity. BcF32 SlowDownTick = BcClamp( Tick * 10.0f, 0.0f, 1.0f ); Velocity_ -= ( Velocity_ * SlowDownTick ); if( Velocity_.magnitude() > MaxVelocity_ ) { Velocity_ = Velocity_.normal() * MaxVelocity_; } // Set local position. Entity->setLocalPosition( LocalPosition ); // Handle health + energy. Health_ = BcClamp( Health_, 0.0f, 100.0f ); Energy_ = BcClamp( Energy_ + ( EnergyChargeRate_ * Tick ), 0.0f, 100.0f ); // Weapon timers. WeaponATimer_ = BcMax( WeaponATimer_ - Tick, -1.0f ); WeaponBTimer_ = BcMax( WeaponBTimer_ - Tick, -1.0f ); MoveTimer_ = BcMax( MoveTimer_ - Tick, -1.0f ); // Health/energy bars. OsClient* Client = OsCore::pImpl()->getClient( 0 ); BcF32 Width = BcF32( Client->getWidth() ) * 0.5f; BcF32 Height = BcF32( Client->getHeight() ) * 0.5f; MaMat4d Projection; Projection.orthoProjection( -Width, Width, Height, -Height, -1.0f, 1.0f ); Canvas_->pushMatrix( Projection ); Canvas_->setMaterialComponent( Material_ ); auto ScreenPos = View_->getScreenPosition( getParentEntity()->getWorldPosition() ); ScreenPos -= MaVec2d( 0.0f, Height / 8.0f ); auto TLPos = ScreenPos - MaVec2d( Width / 16.0f, Height / 64.0f ); auto BRPos = ScreenPos + MaVec2d( Width / 16.0f, Height / 64.0f ); // Draw background. Canvas_->drawBox( TLPos, BRPos, RsColour::BLACK, 0 ); // Draw inner bars. TLPos += MaVec2d( 1.0f, 1.0f ); BRPos -= MaVec2d( 1.0f, 1.0f ); auto HealthTL = MaVec2d( TLPos.x(), TLPos.y() ); auto HealthBR = MaVec2d( TLPos.x() + ( BRPos.x() - TLPos.x() ) * ( Health_ / 100.0f ), ( TLPos.y() + BRPos.y() ) * 0.5f ); auto EnergyTL = MaVec2d( TLPos.x(), ( TLPos.y() + BRPos.y() ) * 0.5f ); auto EnergyBR = MaVec2d( TLPos.x() + ( BRPos.x() - TLPos.x() ) * ( Energy_ / 100.0f ), BRPos.y() ); Canvas_->drawBox( HealthTL, HealthBR, RsColour::GREEN, 0 ); Canvas_->drawBox( EnergyTL, EnergyBR, RsColour::BLUE, 0 ); Canvas_->popMatrix( ); ScnDebugRenderComponent::pImpl()->drawLine( LocalPosition, TargetPosition_, RsColour::WHITE, 0 ); Super::update( Tick ); }
////////////////////////////////////////////////////////////////////////// // update void OsClientWindows::update() { // Update mouse if we're in focus. if( ::GetActiveWindow() == hWnd_ ) { POINT MousePosition; POINT WindowPosition; RECT Rect; // Get window rect in screen space. ::GetWindowRect( hWnd_, &Rect ); // Screen space cood of the client area. WindowPosition.x = 0; WindowPosition.y = 0; ::ClientToScreen( hWnd_, &WindowPosition ); // Get the cursor position ::GetCursorPos( &MousePosition ); const BcS32 WX = ( Rect.right - Rect.left ); const BcS32 WY = ( Rect.bottom - Rect.top ); MouseDelta_.x( BcF32( MousePosition.x - ( Rect.left + ( WX / 2 ) ) ) ); MouseDelta_.y( BcF32( MousePosition.y - ( Rect.top + ( WY / 2 ) ) ) ); MousePos_ += MouseDelta_; MousePos_.x( BcClamp( MousePos_.x(), 0.0f, BcF32( WX ) ) ); MousePos_.y( BcClamp( MousePos_.y(), 0.0f, BcF32( WY ) ) ); // Smooth out delta const MaVec2d TempOld = MouseDelta_; MouseDelta_ = ( MousePrevDelta_ + MouseDelta_ ) * 0.5f; MousePrevDelta_ = TempOld; // Lock to centre of screen if we're in focus. if( MouseLocked_ ) { ::SetCursorPos( Rect.left + ( WX / 2 ), Rect.top + ( WY / 2 ) ); } // Send event if moved. if( MouseDelta_.magnitude() > 0.5f ) { OsEventInputMouse Event; Event.DeviceID_ = 0; Event.MouseX_ = (BcS16)MousePosition.x - (BcS16)WindowPosition.x; Event.MouseY_ = (BcS16)MousePosition.y - (BcS16)WindowPosition.y; Event.MouseDX_ = MouseDelta_.x(); Event.MouseDY_ = MouseDelta_.y(); Event.NormalisedX_ = BcF32( (BcS32)Event.MouseX_ - ( (BcS32)getWidth() / 2 ) ) / BcF32( (BcS32)getWidth() / 2 ); Event.NormalisedY_ = BcF32( (BcS32)Event.MouseY_ - ( (BcS32)getHeight() / 2 ) ) / BcF32( (BcS32)getHeight() / 2 ); // Legacy... PrevMouseX_ = Event.MouseX_; PrevMouseY_ = Event.MouseY_; Event.ButtonCode_ = 0; OsCore::pImpl()->publish( osEVT_INPUT_MOUSEMOVE, Event ); // TODO: REMOVE OLD! EvtPublisher::publish( osEVT_INPUT_MOUSEMOVE, Event ); } } }
////////////////////////////////////////////////////////////////////////// // tickState void GaGameUnit::tickState( BcFixed Delta ) { PrevState_ = CurrState_; NextState_ = CurrState_; //if( NextState_.Velocity_.magnitudeSquared() > 0.0f ) { NextState_.Position_ += NextState_.Velocity_ * Delta; if( Behaviour_ != BEHAVIOUR_DAMAGE ) { // Check new state is valid. BcFixedVec2d Min( NextState_.Position_ - ( Desc_.Size_ * 0.9f ) ); BcFixedVec2d Max( NextState_.Position_ + ( Desc_.Size_ * 0.9f ) ); GaGameUnitIDList FoundUnits; pSimulator_->findUnits( FoundUnits, Min, Max, ID_, 0x3 ); // Move unit away from it's nearest one. if( FoundUnits.size() != 0 ) { BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 0x3 ); GaGameUnit* pGameUnit = pSimulator_->getUnit( NearestUnit ); if( pGameUnit != NULL ) { BcFixedVec2d Direction = ( CurrState_.Position_ - pGameUnit->CurrState_.Position_ ).normal(); if( Direction.dot( NextState_.Velocity_.normal() ) > 0.0f || NextState_.Velocity_.magnitudeSquared() == 0.0f ) { BcFixedVec2d RandomOffset( (int)( pSimulator_->rand() % 64 ), (int)( pSimulator_->rand() % 64 ) ); NextState_ = CurrState_; NextState_.Velocity_ = NextState_.Velocity_ * 0.4f + ( Direction * Desc_.MoveSpeed_ ) * 0.6f; NextState_.Position_ += NextState_.Velocity_ * Delta + ( RandomOffset / 4096.0f ); } } else { NextState_ = CurrState_; } } } } // WalkTimer_ -= NextState_.Velocity_.magnitude() * Delta; if( WalkTimer_ < 0.0f ) { GaTopState::pImpl()->playSound( "Walk", getPosition() ); WalkTimer_ += ( Desc_.MoveSpeed_ + (BcAbs( BcRandom::Global.randReal() ) * 0.02f ) ) * 0.2f; } // Clamp position and move away. BcFixed HW = ( 1280.0f * 0.5f ) / 32.0f - 1.0f; BcFixed HH = ( 720.0f * 0.5f ) / 32.0f - 1.0f; BcFixedVec2d ClampedPosition; ClampedPosition.x( BcClamp( NextState_.Position_.x(), -HW, HW ) ); ClampedPosition.y( BcClamp( NextState_.Position_.y(), -HH, HH ) ); if( NextState_.Position_ != ClampedPosition ) { BcFixedVec2d RandomOffset( (int)( pSimulator_->rand() % 64 ), (int)( pSimulator_->rand() % 64 ) ); NextState_.Velocity_ += RandomOffset / 4096.0f; NextState_.Position_ = ClampedPosition; } }
////////////////////////////////////////////////////////////////////////// // onMouseEvent eEvtReturn GaGameComponent::onMouseEvent( EvtID ID, const OsEventInputMouse& Event ) { // Convert to rendering space. OsClient* pClient = OsCore::pImpl()->getClient( 0 ); BcReal HW = static_cast< BcReal >( pClient->getWidth() ) / 2.0f; BcReal HH = static_cast< BcReal >( pClient->getHeight() ) / 2.0f; CursorPosition_.set( Event.MouseX_ - HW, Event.MouseY_ - HH ); GameCursorPosition_ = CursorPosition_ / 32.0f; EndGameCursorPosition_ = GameCursorPosition_; if( MouseDown_ && ( StartGameCursorPosition_ - EndGameCursorPosition_ ).magnitudeSquared() > BcFixed( 8.0f ) ) { BoxSelection_ = BcTrue; } if( ID == osEVT_INPUT_MOUSEDOWN ) { StartGameCursorPosition_ = GameCursorPosition_; MouseDown_ = BcTrue; BoxSelection_ = BcFalse; } else if( ID == osEVT_INPUT_MOUSEUP ) { EndGameCursorPosition_ = GameCursorPosition_; MouseDown_ = BcFalse; GaGameUnitIDList FoundUnits; if( BoxSelection_ ) { pSimulator_->findUnits( FoundUnits, StartGameCursorPosition_, EndGameCursorPosition_, BcErrorCode, 1 << TeamID_ ); } else { pSimulator_->findUnits( FoundUnits, GameCursorPosition_, 0.8f, BcErrorCode, 1 << TeamID_ ); while( FoundUnits.size() > 1 ) { FoundUnits.pop_back(); } } // If we found units, then set selection. if( FoundUnits.size() > 0 ) { UnitSelection_ = FoundUnits; } else { // If we aren't box selection do action. if( BoxSelection_ == BcFalse ) { BcU32 TargetUnitID = BcErrorCode; // Determine if it's an attack move or not. pSimulator_->findUnits( FoundUnits, GameCursorPosition_, 0.8f, BcErrorCode, 1 << ( 1 - TeamID_ ) ); while( FoundUnits.size() > 1 ) { FoundUnits.pop_back(); } if( FoundUnits.size() == 1 ) { TargetUnitID = FoundUnits[ 0 ]; } // Otherwise, tell found units to move. BcFixedVec2d CentralPosition; BcFixed Divisor; for( BcU32 Idx = 0; Idx < UnitSelection_.size(); ++Idx ) { GaGameUnit* pGameUnit( pSimulator_->getUnit( UnitSelection_[ Idx ] ) ); if( pGameUnit != NULL ) { CentralPosition += pGameUnit->getPosition(); Divisor += 1.0f; } } if( UnitSelection_.size() > 0 && Divisor > 0.0f ) { CentralPosition /= Divisor; GameCursorPosition_ = BcFixedVec2d( ( GameCursorPosition_.x() ), ( GameCursorPosition_.y() ) ); BcFixed PlayfieldHW = 1280.0f * 0.5f / 32.0f; BcFixed PlayfieldHH = 720.0f * 0.5f / 32.0f; for( BcU32 Idx = 0; Idx < UnitSelection_.size(); ++Idx ) { GaGameUnit* pGameUnit( pSimulator_->getUnit( UnitSelection_[ Idx ] ) ); if( pGameUnit != NULL ) { if( TargetUnitID == BcErrorCode ) { GaGameUnitMoveEvent Event; Event.UnitID_ = pGameUnit->getID(); Event.Position_ = ( ( pGameUnit->getPosition() - CentralPosition ) * 0.0f ) + GameCursorPosition_; Event.Position_.x( BcClamp( Event.Position_.x(), -PlayfieldHW, PlayfieldHW ) ); Event.Position_.y( BcClamp( Event.Position_.y(), -PlayfieldHH, PlayfieldHH ) ); Event.IsAttackMove_ = AttackMove_; pSimulator_->publish( gaEVT_UNIT_MOVE, Event ); } else { GaGameUnitAttackEvent Event; Event.UnitID_ = pGameUnit->getID(); Event.TargetUnitID_ = TargetUnitID; pSimulator_->publish( gaEVT_UNIT_ATTACK, Event ); } } } } // Toggle off attack move. AttackMove_ = BcFalse; } else { // If we were box selecting clear selection. UnitSelection_.clear(); } } BoxSelection_ = BcFalse; } return evtRET_PASS; }
////////////////////////////////////////////////////////////////////////// // randRange BcS32 BcRandom::randRange( BcS32 Min, BcS32 Max ) { return BcClamp( ( Min + ( rand() % ( 1 + Max - Min ) ) ), Min, Max ); }