2018-06-19 09:06:54 +00:00
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System ;
using System.Linq ;
using Xenko.Core ;
using Xenko.Core.Mathematics ;
using Xenko.Animations ;
using Xenko.Engine ;
using Xenko.Input ;
using Xenko.Physics ;
using Xenko.Rendering.Sprites ;
namespace PhysicsSample
{
/// <summary>
/// This script will interface the Physics character controller of the entity to move the character around
/// Will also animate the sprite of the entity, between run and idle.
/// </summary>
public class CharacterScript : SyncScript
{
[Flags]
enum PlayerState
{
Idle = 0x0 ,
Run = 0x1 ,
Jump = 0x2
}
private const float speed = 0.075f ;
private CharacterComponent playerController ;
private SpriteComponent playerSprite ;
[DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting)
private bool movingToTarget ;
[DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting)
private PlayerState oldState = PlayerState . Idle ;
[DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting)
private Vector3 oldDirection = Vector3 . Zero ;
[DataMember(Mask = LiveScriptingMask)] // keep the value when reloading the script (live-scripting)
private Vector3 autoPilotTarget = Vector3 . Zero ;
void PlayIdle ( )
{
var sheet = ( ( SpriteFromSheet ) playerSprite . SpriteProvider ) . Sheet ;
SpriteAnimation . Play ( playerSprite , sheet . FindImageIndex ( "idle0" ) , sheet . FindImageIndex ( "idle4" ) , AnimationRepeatMode . LoopInfinite , 7 ) ;
}
void PlayRun ( )
{
var sheet = ( ( SpriteFromSheet ) playerSprite . SpriteProvider ) . Sheet ;
SpriteAnimation . Play ( playerSprite , sheet . FindImageIndex ( "run0" ) , sheet . FindImageIndex ( "run4" ) , AnimationRepeatMode . LoopInfinite , 12 ) ;
}
public override void Start ( )
{
playerSprite = Entity . Get < SpriteComponent > ( ) ;
playerController = Entity . Get < CharacterComponent > ( ) ;
//Please remember that in the GameStudio element the parameter Step Height is extremely important, it not set properly it will cause the entity to snap fast to the ground
playerController . JumpSpeed = 5.0f ;
2018-12-01 13:27:13 +00:00
playerController . Gravity = new Vector3 ( 0.0f , - 10.0f , 0.0f ) ;
2018-06-19 09:06:54 +00:00
playerController . FallSpeed = 10.0f ;
playerController . ProcessCollisions = true ;
if ( ! IsLiveReloading )
{
Script . AddTask ( async ( ) = >
{
while ( Game . IsRunning )
{
var collision = await playerController . NewCollision ( ) ;
// Stop if we collide from side
foreach ( var contact in collision . Contacts )
{
if ( contact . Normal . X < - 0.5f | | contact . Normal . X > 0.5f )
{
movingToTarget = false ;
break ;
}
}
}
} ) ;
PlayIdle ( ) ;
}
}
public override void Update ( )
{
var playerState = PlayerState . Idle ;
var playerDirection = Vector3 . Zero ;
// -- Keyboard Inputs
// Space bar = jump
if ( Input . IsKeyDown ( Keys . Space ) )
{
playerState | = PlayerState . Jump ;
}
// Left - right = run
if ( Input . IsKeyDown ( Keys . Right ) )
{
movingToTarget = false ;
playerState | = PlayerState . Run ;
playerDirection = Vector3 . UnitX * speed ;
}
else if ( Input . IsKeyDown ( Keys . Left ) )
{
movingToTarget = false ;
playerState | = PlayerState . Run ;
playerDirection = - Vector3 . UnitX * speed ;
}
// -- Pointer (mouse/touch)
foreach ( var pointerEvent in Input . PointerEvents . Where ( pointerEvent = > pointerEvent . EventType = = PointerEventType . Pressed ) )
{
if ( ! movingToTarget )
{
var screenX = ( pointerEvent . Position . X - 0.5f ) * 2.0f ;
screenX * = 8.75f ;
autoPilotTarget = new Vector3 ( screenX , 0 , 0 ) ;
movingToTarget = true ;
}
else
{
playerState | = PlayerState . Jump ;
}
}
// -- Logic
// are we autopiloting?
if ( movingToTarget )
{
var direction = autoPilotTarget - Entity . Transform . Position ;
direction . Y = 0 ;
//should we stop?
var length = direction . Length ( ) ;
if ( length < speed )
{
movingToTarget = false ;
playerDirection = Vector3 . Zero ;
playerState = PlayerState . Idle ;
}
else
{
direction . Normalize ( ) ;
playerDirection = ( direction . X > 0 ? Vector3 . UnitX : - Vector3 . UnitX ) * speed ;
playerState | = PlayerState . Run ;
}
}
// did we start jumping?
if ( playerState . HasFlag ( PlayerState . Jump ) & & ! oldState . HasFlag ( PlayerState . Jump ) )
{
playerController . Jump ( ) ;
}
// did we just land?
if ( oldState . HasFlag ( PlayerState . Jump ) )
{
if ( ! playerController . IsGrounded )
{
//force set jump flag
if ( ! playerState . HasFlag ( PlayerState . Jump ) )
{
playerState | = PlayerState . Jump ;
// Mantain motion
playerDirection = oldDirection ;
}
}
else if ( playerController . IsGrounded )
{
//force clear jump flag
if ( playerState . HasFlag ( PlayerState . Jump ) )
{
playerState ^ = PlayerState . Jump ;
}
}
}
// did we start running?
if ( playerState . HasFlag ( PlayerState . Run ) & & ! oldState . HasFlag ( PlayerState . Run ) )
{
PlayRun ( ) ;
}
// did we stop running?
else if ( ! playerState . HasFlag ( PlayerState . Run ) & & oldState . HasFlag ( PlayerState . Run ) )
{
PlayIdle ( ) ;
}
// movement logic
if ( oldDirection ! = playerDirection )
{
playerController . Move ( playerDirection ) ;
if ( playerState . HasFlag ( PlayerState . Run ) )
{
if ( ( playerDirection . X > 0 & & Entity . Transform . Scale . X < 0 ) | |
( playerDirection . X < 0 & & Entity . Transform . Scale . X > 0 ) )
{
Entity . Transform . Scale . X * = - 1.0f ;
}
}
}
// Store current state for next frame
oldState = playerState ;
oldDirection = playerDirection ;
}
}
}