Start work on rain particles.

This commit is contained in:
UnknownShadow200 2015-11-21 17:44:47 +11:00
parent 42381461be
commit dff4877fd6
10 changed files with 128 additions and 76 deletions

View File

@ -130,8 +130,10 @@
<Compile Include="Entities\LocalPlayer.cs" />
<Compile Include="Entities\LocationUpdate.cs" />
<Compile Include="Entities\NetPlayer.cs" />
<Compile Include="Entities\Particles\CollidableParticle.cs" />
<Compile Include="Entities\Particles\Particle.cs" />
<Compile Include="Entities\Particles\ParticleManager.cs" />
<Compile Include="Entities\Particles\RainParticle.cs" />
<Compile Include="Entities\Particles\TerrainParticle.cs" />
<Compile Include="Entities\PhysicsEntity.cs" />
<Compile Include="Entities\Player.cs" />

View File

@ -0,0 +1,64 @@
using System;
using OpenTK;
namespace ClassicalSharp.Particles {
public abstract class CollidableParticle : Particle {
const float gravity = 3.4f;
public CollidableParticle( Game game, Vector3 pos, Vector3 velocity, double lifetime )
: base( game, pos, velocity, lifetime ) {
}
public override bool Tick( double delta ) {
lastPos = Position = nextPos;
byte curBlock = game.Map.SafeGetBlock( (int)Position.X, (int)Position.Y, (int)Position.Z );
if( !CanPassThrough( curBlock ) ) return true;
Velocity.Y -= gravity * (float)delta;
int startY = (int)Math.Floor( Position.Y );
Position += Velocity * (float)delta * 3;
int endY = (int)Math.Floor( Position.Y );
Utils.Clamp( ref Position.X, 0, game.Map.Width - 0.01f );
Utils.Clamp( ref Position.Z, 0, game.Map.Length - 0.01f );
if( Velocity.Y > 0 ) {
for( int y = startY; y <= endY && TestY( y, false ); y++ );
} else {
for( int y = startY; y >= endY && TestY( y, true ); y-- );
}
nextPos = Position;
Position = lastPos;
return base.Tick( delta );
}
bool TestY( int y, bool topFace ) {
if( y < 0 ) {
Position.Y = nextPos.Y = lastPos.Y = 0 + Entity.Adjustment;
Velocity = Vector3.Zero;
return false;
}
byte block = game.Map.SafeGetBlock( (int)Position.X, y, (int)Position.Z );
if( CanPassThrough( block ) ) return true;
float collideY = y;
if( topFace )
collideY += game.BlockInfo.Height[block];
bool collide = topFace ? (Position.Y < collideY) : (Position.Y > collideY );
if( collide ) {
float adjust = topFace ? Entity.Adjustment : -Entity.Adjustment;
Position.Y = nextPos.Y = lastPos.Y = collideY + adjust;
Velocity = Vector3.Zero;
return false;
}
return true;
}
bool CanPassThrough( byte block ) {
return block == 0 || game.BlockInfo.IsSprite[block] || game.BlockInfo.IsLiquid[block];
}
}
}

View File

@ -7,7 +7,6 @@ namespace ClassicalSharp.Particles {
public Vector3 Position;
public Vector3 Velocity;
public TextureRec Rectangle;
public float Lifetime;
protected Game game;
protected Vector3 lastPos, nextPos;
@ -16,12 +15,11 @@ namespace ClassicalSharp.Particles {
public abstract void Dispose();
public Particle( Game game, Vector3 pos, Vector3 velocity, double lifetime, TextureRec rec ) {
public Particle( Game game, Vector3 pos, Vector3 velocity, double lifetime ) {
this.game = game;
Position = lastPos = nextPos = pos;
Velocity = velocity;
Lifetime = (float)lifetime;
Rectangle = rec;
}
public virtual bool Tick( double delta ) {

View File

@ -0,0 +1,31 @@
using System;
using OpenTK;
namespace ClassicalSharp.Particles {
public sealed class RainParticle : CollidableParticle {
static Vector2 rainSize = new Vector2( 1/8f, 1/8f );
static TextureRec rec = new TextureRec( 2/128f, 14/128f, 3/128f, 2/128f );
public RainParticle( Game game, Vector3 pos, Vector3 velocity, double lifetime )
: base( game, pos, velocity, lifetime ) {
}
public override void Render( double delta, float t, VertexPos3fTex2fCol4b[] vertices, ref int index ) {
Position = Vector3.Lerp( lastPos, nextPos, t );
Vector3 p111, p121, p212, p222;
Utils.CalcBillboardPoints( rainSize, Position, ref game.View,
out p111, out p121, out p212, out p222 );
Map map = game.Map;
FastColour col = map.IsLit( Vector3I.Floor( Position ) ) ? map.Sunlight : map.Shadowlight;
vertices[index++] = new VertexPos3fTex2fCol4b( p111, rec.U1, rec.V2, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p121, rec.U1, rec.V1, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p222, rec.U2, rec.V1, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p212, rec.U2, rec.V2, col );
}
public override void Dispose() {
}
}
}

View File

@ -3,13 +3,13 @@ using OpenTK;
namespace ClassicalSharp.Particles {
public sealed class TerrainParticle : Particle {
public sealed class TerrainParticle : CollidableParticle {
const float gravity = 3.4f;
static Vector2 terrainSize = new Vector2( 1/8f, 1/8f );
TextureRec rec;
public TerrainParticle( Game game, Vector3 pos, Vector3 velocity, double lifetime, TextureRec rec )
: base( game, pos, velocity, lifetime, rec ) {
: base( game, pos, velocity, lifetime ) {
this.rec = rec;
}
public override void Render( double delta, float t, VertexPos3fTex2fCol4b[] vertices, ref int index ) {
@ -20,60 +20,10 @@ namespace ClassicalSharp.Particles {
Map map = game.Map;
FastColour col = map.IsLit( Vector3I.Floor( Position ) ) ? map.Sunlight : map.Shadowlight;
vertices[index++] = new VertexPos3fTex2fCol4b( p111, Rectangle.U1, Rectangle.V2, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p121, Rectangle.U1, Rectangle.V1, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p222, Rectangle.U2, Rectangle.V1, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p212, Rectangle.U2, Rectangle.V2, col );
}
public override bool Tick( double delta ) {
lastPos = Position = nextPos;
byte curBlock = game.Map.SafeGetBlock( (int)Position.X, (int)Position.Y, (int)Position.Z );
if( !CanPassThrough( curBlock ) ) return true;
Velocity.Y -= gravity * (float)delta;
int startY = (int)Math.Floor( Position.Y );
Position += Velocity * (float)delta * 3;
int endY = (int)Math.Floor( Position.Y );
Utils.Clamp( ref Position.X, 0, game.Map.Width - 0.01f );
Utils.Clamp( ref Position.Z, 0, game.Map.Length - 0.01f );
if( Velocity.Y > 0 ) {
for( int y = startY; y <= endY && TestY( y, false ); y++ );
} else {
for( int y = startY; y >= endY && TestY( y, true ); y-- );
}
nextPos = Position;
Position = lastPos;
return base.Tick( delta );
}
bool TestY( int y, bool topFace ) {
if( y < 0 ) {
Position.Y = nextPos.Y = lastPos.Y = 0 + Entity.Adjustment;
Velocity = Vector3.Zero;
return false;
}
byte block = game.Map.SafeGetBlock( (int)Position.X, y, (int)Position.Z );
if( CanPassThrough( block ) ) return true;
float collideY = y;
if( topFace )
collideY += game.BlockInfo.Height[block];
bool collide = topFace ? (Position.Y < collideY) : (Position.Y > collideY );
if( collide ) {
float adjust = topFace ? Entity.Adjustment : -Entity.Adjustment;
Position.Y = nextPos.Y = lastPos.Y = collideY + adjust;
Velocity = Vector3.Zero;
return false;
}
return true;
}
bool CanPassThrough( byte block ) {
return block == 0 || game.BlockInfo.IsSprite[block] || game.BlockInfo.IsLiquid[block];
vertices[index++] = new VertexPos3fTex2fCol4b( p111, rec.U1, rec.V2, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p121, rec.U1, rec.V1, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p222, rec.U2, rec.V1, col );
vertices[index++] = new VertexPos3fTex2fCol4b( p212, rec.U2, rec.V2, col );
}
public override void Dispose() {

View File

@ -30,9 +30,9 @@ namespace ClassicalSharp {
Key mapLeft, mapMiddle, mapRight;
void LoadMouseToKeyMappings() {
mapLeft = Options.GetKey( OptionsKey.MouseLeft, Key.Unknown );
mapMiddle = Options.GetKey( OptionsKey.MouseMiddle, Key.Unknown );
mapRight = Options.GetKey( OptionsKey.MouseRight, Key.Unknown );
mapLeft = Options.GetEnum( OptionsKey.MouseLeft, Key.Unknown );
mapMiddle = Options.GetEnum( OptionsKey.MouseMiddle, Key.Unknown );
mapRight = Options.GetEnum( OptionsKey.MouseRight, Key.Unknown );
}
public KeyMap Keys;

View File

@ -55,7 +55,7 @@ namespace ClassicalSharp {
string[] names = KeyBinding.GetNames( typeof( KeyBinding ) );
for( int i = 0; i < names.Length; i++ ) {
string key = "key-" + names[i];
Key mapping = Options.GetKey( key, Keys[i] );
Key mapping = Options.GetEnum( key, Keys[i] );
if( !IsReservedKey( mapping ) )
Keys[i] = mapping;
}

View File

@ -99,7 +99,7 @@ namespace ClassicalSharp.Hotkeys {
// Then try to parse the key and value
Key key; byte flags; bool moreInput;
if( !Utils.TryParseKey( strKey, Key.Unknown, out key ) ||
if( !Utils.TryParseEnum( strKey, Key.Unknown, out key ) ||
!Byte.TryParse( strFlags, out flags ) ||
!Boolean.TryParse( strMoreInput, out moreInput ) ||
strText.Length == 0 ) {

View File

@ -23,6 +23,14 @@ namespace ClassicalSharp {
public const string VSync = "vsync";
}
public enum FpsLimit {
LimitVSync,
Limit30FPS,
Limit60FPS,
Limit120FPS,
LimitNone,
}
public static class Options {
public static Dictionary<string, string> OptionsSet = new Dictionary<string, string>();
@ -64,15 +72,15 @@ namespace ClassicalSharp {
return valueFloat;
}
public static Key GetKey( string key, Key defValue ) {
public static T GetEnum<T>( string key, T defValue ) {
string value = Options.Get( key.ToLower() );
if( value == null ) {
Set( key, defValue );
return defValue;
}
Key mapping;
if( !Utils.TryParseKey( value, defValue, out mapping ) )
T mapping;
if( !Utils.TryParseEnum( value, defValue, out mapping ) )
Options.Set( key, defValue );
return mapping;
}

View File

@ -128,16 +128,15 @@ namespace ClassicalSharp {
/// <summary> Attempts to caselessly parse the given string as a Key enum member,
/// returning defValue if there was an error parsing. </summary>
public static bool TryParseKey( string value, Key defValue, out Key key ) {
Key mapping;
public static bool TryParseEnum<T>( string value, T defValue, out T result ) {
T mapping;
try {
mapping = (Key)Enum.Parse( typeof( Key ), value, true );
mapping = (T)Enum.Parse( typeof( T ), value, true );
} catch( ArgumentException ) {
key = defValue;
result = defValue;
return false;
}
key = mapping;
}
result = mapping;
return true;
}