More physics (still to go: saplings)

This commit is contained in:
UnknownShadow200 2015-09-25 20:21:05 +10:00
parent 808d66ea6c
commit 6c69baeb38
6 changed files with 417 additions and 87 deletions

View File

@ -366,9 +366,9 @@ namespace ClassicalSharp {
}
public void UpdateBlock( int x, int y, int z, byte block ) {
int oldHeight = Map.GetLightHeight( x, z );
int oldHeight = Map.GetLightHeight( x, z ) + 1;
Map.SetBlock( x, y, z, block );
int newHeight = Map.GetLightHeight( x, z );
int newHeight = Map.GetLightHeight( x, z ) + 1;
MapRenderer.RedrawBlock( x, y, z, block, oldHeight, newHeight );
}

View File

@ -132,7 +132,7 @@ namespace ClassicalSharp {
byte block = mapData[mapIndex];
if( info.BlocksLight[block] ) {
heightmap[index] = (short)( y - 1 );
return y;
return y - 1;
}
mapIndex -= oneY;
}

View File

@ -149,19 +149,15 @@ namespace ClassicalSharp {
}
public void RedrawBlock( int x, int y, int z, byte block, int oldHeight, int newHeight ) {
int cx = x >> 4;
int cy = y >> 4;
int cz = z >> 4;
int cx = x >> 4, bX = x & 0x0F;
int cy = y >> 4, bY = y & 0x0F;
int cz = z >> 4, bZ = z & 0x0F;
// NOTE: It's a lot faster to only update the chunks that are affected by the change in shadows,
// rather than the entire column.
int newLightcy = newHeight == -1 ? 0 : newHeight >> 4;
int oldLightcy = oldHeight == -1 ? 0 : oldHeight >> 4;
ResetChunkAndBelow( cx, cy, cz, newLightcy, oldLightcy );
int bX = x & 0x0F; // % 16
int bY = y & 0x0F;
int bZ = z & 0x0F;
int newLightcy = newHeight < 0 ? 0 : newHeight >> 4;
int oldLightcy = oldHeight < 0 ? 0 : oldHeight >> 4;
ResetChunkAndBelow( cx, cy, cz, newLightcy, oldLightcy );
if( bX == 0 && cx > 0 ) ResetChunkAndBelow( cx - 1, cy, cz, newLightcy, oldLightcy );
if( bY == 0 && cy > 0 ) ResetChunkAndBelow( cx, cy - 1, cz, newLightcy, oldLightcy );
if( bZ == 0 && cz > 0 ) ResetChunkAndBelow( cx, cy, cz - 1, newLightcy, oldLightcy );

View File

@ -9,7 +9,7 @@ namespace ClassicalSharp.Singleplayer {
Game game;
public Map map;
BlockInfo info;
int width, length, height, oneY;
int width, length, height, oneY, volume;
const uint tickMask = 0xF8000000;
const uint posMask = 0x07FFFFFF;
@ -50,10 +50,15 @@ namespace ClassicalSharp.Singleplayer {
return true;
}
int tickCount = 0;
public void Tick() {
//if( (tickCount % 5) == 0 ) {
TickLava();
TickWater();
TickFalling();
//}
tickCount++;
TickRandomBlocks();
}
public void OnBlockPlaced( int x, int y, int z, byte block ) {
@ -76,8 +81,72 @@ namespace ClassicalSharp.Singleplayer {
length = map.Length;
height = map.Height;
oneY = height * width;
volume = height * width * length;
}
#region General
// TODO: tree growing
void TickRandomBlocks() {
for( int y = 0; y < height; y += 16 ) {
for( int z = 0; z < length; z += 16 ) {
for( int x = 0; x < width; x += 16 ) {
int lo = (y * length + z) * width + x;
int hi = ((y + 15) * length + (z + 15)) * width + (x + 15 );
HandleBlock( rnd.Next( lo, hi ) );
HandleBlock( rnd.Next( lo, hi ) );
HandleBlock( rnd.Next( lo, hi ) );
}
}
}
}
void HandleBlock( int posIndex ) {
int x = posIndex % width;
int y = posIndex / oneY; // posIndex / (width * length)
int z = (posIndex / width) % length;
byte block = map.mapData[posIndex];
switch( block ) {
case (byte)Block.Dirt:
if( y > map.GetLightHeight( x, z ) )
game.UpdateBlock( x, y, z, (byte)Block.Grass );
break;
case (byte)Block.Grass:
if( y <= map.GetLightHeight( x, z ) ) {
game.UpdateBlock( x, y, z, (byte)Block.Dirt );
}
break;
case (byte)Block.Dandelion:
case (byte)Block.Rose:
case (byte)Block.BrownMushroom:
case (byte)Block.RedMushroom:
if( y <= map.GetLightHeight( x, z ) )
game.UpdateBlock( x, y, z, (byte)Block.Air );
break;
case (byte)Block.Sapling:
game.UpdateBlock( x, y, z, (byte)Block.ForestGreenWool );
break;
case (byte)Block.Sand:
case (byte)Block.Gravel:
if( y > 0 ) PropagateFalling( posIndex, x, y, z, block, 0 );
break;
case (byte)Block.Lava:
HandleLava( posIndex, x, y, z );
break;
case (byte)Block.Water:
HandleWater( posIndex, x, y, z );
break;
}
}
#endregion
#region Lava
Queue<uint> Lava = new Queue<uint>();
@ -94,16 +163,19 @@ namespace ClassicalSharp.Singleplayer {
int x = posIndex % width;
int y = posIndex / oneY; // posIndex / (width * length)
int z = (posIndex / width) % length;
if( x > 0 ) PropagateLava( posIndex - 1, x - 1, y, z );
if( x < width - 1 ) PropagateLava( posIndex + 1, x + 1, y, z );
if( z > 0 ) PropagateLava( posIndex - width, x, y, z - 1 );
if( z < length - 1 ) PropagateLava( posIndex + width, x, y, z + 1 );
if( y > 0 ) PropagateLava( posIndex - oneY, x, y - 1, z );
HandleLava( posIndex, x, y, z );
}
}
}
void HandleLava( int posIndex, int x, int y, int z ) {
if( x > 0 ) PropagateLava( posIndex - 1, x - 1, y, z );
if( x < width - 1 ) PropagateLava( posIndex + 1, x + 1, y, z );
if( z > 0 ) PropagateLava( posIndex - width, x, y, z - 1 );
if( z < length - 1 ) PropagateLava( posIndex + width, x, y, z + 1 );
if( y > 0 ) PropagateLava( posIndex - oneY, x, y - 1, z );
}
void PropagateLava( int posIndex, int x, int y, int z ) {
byte block = map.mapData[posIndex];
if( block == (byte)Block.Water || block == (byte)Block.StillWater ) {
@ -132,16 +204,19 @@ namespace ClassicalSharp.Singleplayer {
int x = posIndex % width;
int y = posIndex / oneY; // posIndex / (width * length)
int z = (posIndex / width) % length;
if( x > 0 ) PropagateWater( posIndex - 1, x - 1, y, z );
if( x < width - 1 ) PropagateWater( posIndex + 1, x + 1, y, z );
if( z > 0 ) PropagateWater( posIndex - width, x, y, z - 1 );
if( z < length - 1 ) PropagateWater( posIndex + width, x, y, z + 1 );
if( y > 0 ) PropagateWater( posIndex - oneY, x, y - 1, z );
HandleWater( posIndex, x, y, z );
}
}
}
void HandleWater( int posIndex, int x, int y, int z ) {
if( x > 0 ) PropagateWater( posIndex - 1, x - 1, y, z );
if( x < width - 1 ) PropagateWater( posIndex + 1, x + 1, y, z );
if( z > 0 ) PropagateWater( posIndex - width, x, y, z - 1 );
if( z < length - 1 ) PropagateWater( posIndex + width, x, y, z + 1 );
if( y > 0 ) PropagateWater( posIndex - oneY, x, y - 1, z );
}
void PropagateWater( int posIndex, int x, int y, int z ) {
byte block = map.mapData[posIndex];
if( block == (byte)Block.Lava || block == (byte)Block.StillLava ) {
@ -154,6 +229,52 @@ namespace ClassicalSharp.Singleplayer {
#endregion
#region Sand/Gravel
Queue<uint> Falling = new Queue<uint>();
const uint defFallingTick = 2u << tickShift;
void TickFalling() {
int count = Falling.Count;
for( int i = 0; i < count; i++ ) {
int posIndex, flags;
if( CheckItem( Falling, 0x2, out posIndex, out flags ) ) {
byte block = map.mapData[posIndex];
if( !(block == (byte)Block.Sand || block == (byte)Block.Gravel ) ) continue;
int x = posIndex % width;
int y = posIndex / oneY; // posIndex / (width * length)
int z = (posIndex / width) % length;
if( y > 0 ) PropagateFalling( posIndex, x, y, z, block, flags );
}
}
}
void PropagateFalling( int posIndex, int x, int y, int z, byte block, int flags ) {
byte newBlock = map.mapData[posIndex - oneY];
if( newBlock == 0 || info.IsLiquid[newBlock] ) {
uint newFlags = MakeFallingFlags( newBlock ) << tickShift;
Falling.Enqueue( newFlags | (uint)(posIndex - oneY) );
game.UpdateBlock( x, y, z, oldBlock[flags >> 2] );
game.UpdateBlock( x, y - 1, z, block );
}
}
static byte[] oldBlock = new byte[] { (byte)Block.Air, (byte)Block.StillWater,
(byte)Block.Water, (byte)Block.StillLava, (Byte)Block.Lava };
static uint MakeFallingFlags( byte above ) {
byte flags = 2;
if( above == (byte)Block.StillWater ) flags |= 0x04; // 1
else if( above == (byte)Block.Water ) flags |= 0x08; // 2
else if( above == (byte)Block.StillLava ) flags |= 0x0C; // 3
else if( above == (byte)Block.Lava ) flags |= 0x10; // 4
return flags;
}
#endregion
#region TNT
Vector3[] rayDirs;
@ -188,21 +309,21 @@ namespace ClassicalSharp.Singleplayer {
}
void InitExplosionCache() {
hardness = new float[] { 0, 30, 3, 2.5f, 30, 15, 0, 1.8E+07f, 500, 500, 500, 500, 2.5f,
3, 15, 15, 15, 10, 1, 3, 1.5f, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0,
hardness = new float[] { 0, 30, 3, 2.5f, 30, 15, 0, 1.8E+07f, 500, 500, 500, 500, 2.5f,
3, 15, 15, 15, 10, 1, 3, 1.5f, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0,
0, 0, 30, 30, 30, 30, 30, 0, 7.5f, 30, 6000, 30, 0, 4, 0.5f, 0, 4, 4, 4, 4, 4, 2.5f,
// Note that the 30, 500, 15, 15 are guesses (CeramicTile --> Crate)
30, 500, 15, 15, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30, 500, 15, 15, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
rayDirs = new Vector3[1352];
int index = 0;
// Y bottom and top planes
// Y bottom and top planes
for( float x = -1; x <= 1.001f; x += 2f/15) {
for( float z = -1; z <= 1.001f; z += 2f/15) {
rayDirs[index++] = Vector3.Normalize( x, -1, z );
@ -226,57 +347,5 @@ namespace ClassicalSharp.Singleplayer {
}
#endregion
#region Sapling
// TODO: tree growing
#endregion
#region Grass
// TODO: grass growing
#endregion
#region Sand/Gravel
Queue<uint> Falling = new Queue<uint>();
const uint defFallingTick = 2u << tickShift;
void TickFalling() {
int count = Falling.Count;
for( int i = 0; i < count; i++ ) {
int posIndex, flags;
if( CheckItem( Falling, 0x2, out posIndex, out flags ) ) {
byte block = map.mapData[posIndex];
if( !(block == (byte)Block.Sand || block == (byte)Block.Gravel ) ) continue;
int x = posIndex % width;
int y = posIndex / oneY; // posIndex / (width * length)
int z = (posIndex / width) % length;
if( y > 0 ) PropagateFalling( posIndex - oneY, x, y - 1, z, block, flags );
}
}
}
void PropagateFalling( int posIndex, int x, int y, int z, byte block, int flags ) {
byte newBlock = map.mapData[posIndex];
if( newBlock == 0 || info.IsLiquid[newBlock] ) {
uint newFlags = MakeFallingFlags( newBlock ) << tickShift;
Falling.Enqueue( newFlags | (uint)posIndex );
game.UpdateBlock( x, y, z, oldBlock[flags >> 2] );
game.UpdateBlock( x, y - 1, z, block );
}
}
static byte[] oldBlock = new byte[] { (byte)Block.Air, (byte)Block.StillWater,
(byte)Block.Water, (byte)Block.StillLava, (Byte)Block.Lava };
static uint MakeFallingFlags( byte above ) {
byte flags = 2;
if( above == (byte)Block.StillWater ) flags |= 0x04; // 1
else if( above == (byte)Block.Water ) flags |= 0x08; // 2
else if( above == (byte)Block.StillLava ) flags |= 0x0C; // 3
else if( above == (byte)Block.Lava ) flags |= 0x10; // 4
return flags;
}
#endregion
}
}

View File

@ -98,6 +98,7 @@
<Compile Include="Platform\MacOS\MacOSException.cs" />
<Compile Include="Platform\MacOS\MacOSKeyMap.cs" />
<Compile Include="Platform\MacOS\QuartzDisplayDeviceDriver.cs" />
<Compile Include="Platform\Minimal.cs" />
<Compile Include="Platform\PlatformException.cs" />
<Compile Include="Platform\Windows\API.cs" />
<Compile Include="Platform\Windows\Wgl.cs" />

264
OpenTK/Platform/Minimal.cs Normal file
View File

@ -0,0 +1,264 @@
#if OPENTK_MINIMAL
using System;
// These classes fill in for missing Rectangle, Point, and Size implementations
namespace System.Drawing {
public struct Rectangle {
public static readonly Rectangle Empty = default(Rectangle);
public int X, Y;
public int Width, Height;
public Point Location {
get { return new Point( X, Y ); }
set { X = value.X; Y = value.Y; }
}
public Size Size {
get { return new Size( Width, Height ); }
set { Width = value.Width; Height = value.Height; }
}
public int Left {
get { return X; }
}
public int Top {
get { return Y; }
}
public int Right {
get { return X + Width; }
}
public int Bottom {
get { return Y + Height; }
}
public bool IsEmpty {
get { return Height == 0 && Width == 0 && X == 0 && Y == 0; }
}
public Rectangle( int x, int y, int width, int height ) {
X = x; Y = y;
Width = width; Height = height;
}
public Rectangle( Point loc, Size size ) {
X = loc.X; Y = loc.Y;
Width = size.Width; Height = size.Height;
}
public static Rectangle FromLTRB( int left, int top, int right, int bottom ) {
return new Rectangle( left, top, right - left, bottom - top );
}
public override bool Equals( object obj ) {
return (obj is Rectangle) && Equals( (Rectangle)obj );
}
public bool Equals( Rectangle other ) {
return X == other.X && Y == other.Y && Width == other.Width && Height == other.Height;
}
public override int GetHashCode() {
return 1000000007 * X + 1000000009 * Y +
1000000021 * Width + 1000000033 * Height;
}
public static bool operator == ( Rectangle lhs, Rectangle rhs ) {
return lhs.Equals( rhs );
}
public static bool operator != ( Rectangle lhs, Rectangle rhs ) {
return !(lhs == rhs);
}
public bool Contains(int x, int y) {
return X <= x && x < X + Width && Y <= y && y < Y + Height;
}
public bool Contains( Point pt ) {
return Contains( pt.X, pt.Y );
}
public bool Contains( Rectangle rect ) {
return X <= rect.X && rect.X + rect.Width <= X + Width && Y <= rect.Y && rect.Y + rect.Height <= Y + Height;
}
public override string ToString() {
return X + ", " + Y + " : " + Width + "," + Height;
}
}
public struct Size {
public static readonly Size Empty = default(Size);
public int Width, Height;
public bool IsEmpty {
get { return Width == 0 && Height == 0; }
}
public Size( Point point ) {
Width = point.X; Height = point.Y;
}
public Size( int width, int height ) {
Width = width; Height = height;
}
public static Size Ceiling( SizeF value ) {
return new Size( (int)Math.Ceiling( value.Width ), (int)Math.Ceiling( value.Height ) );
}
public override bool Equals( object obj ) {
return (obj is Size) && Equals( (Size)obj );
}
public bool Equals( Size other ) {
return Width == other.Width && Height == other.Height;
}
public override int GetHashCode() {
return 1000000007 * Width + 1000000009 * Height;
}
public static bool operator == ( Size lhs, Size rhs ) {
return lhs.Width == rhs.Width && lhs.Height == rhs.Height;
}
public static bool operator != ( Size lhs, Size rhs ) {
return !(lhs == rhs);
}
public override string ToString() {
return Width + "," + Height;
}
}
public struct SizeF {
public static readonly SizeF Empty = default(SizeF);
public float Width, Height;
public bool IsEmpty {
get { return Width == 0 && Height == 0; }
}
public SizeF( float width, float height ) {
Width = width; Height = height;
}
public override bool Equals( object obj ) {
return (obj is SizeF) && Equals( (SizeF)obj );
}
public bool Equals( SizeF other ) {
return Width == other.Width && Height == other.Height;
}
public override int GetHashCode() {
return 1000000007 * Width.GetHashCode() +
1000000009 * Height.GetHashCode();
}
public static bool operator == ( SizeF lhs, SizeF rhs ) {
return lhs.Width == rhs.Width && lhs.Height == rhs.Height;
}
public static bool operator != ( SizeF lhs, SizeF rhs ) {
return !(lhs == rhs);
}
public override string ToString() {
return Width + "," + Height;
}
}
public struct Point {
public static readonly Point Empty = default(Point);
public int X, Y;
public bool IsEmpty {
get { return X == 0 && Y == 0; }
}
public Point( Size size ) {
X = size.Width; Y = size.Height;
}
public Point( int x, int y ) {
X = x; Y = y;
}
public override bool Equals( object obj ) {
return (obj is Point) && Equals( (Point)obj );
}
public bool Equals( Point other ) {
return X == other.X && Y == other.Y;
}
public override int GetHashCode() {
return 1000000007 * X + 1000000009 * Y;
}
public static bool operator == ( Point lhs, Point rhs ) {
return lhs.X == rhs.X && lhs.Y == rhs.Y;
}
public static bool operator != ( Point lhs, Point rhs ) {
return !(lhs == rhs);
}
public override string ToString() {
return X + "," + Y;
}
}
public struct Color {
public byte R, G, B, A;
public Color( int r, int g, int b, int a ) {
A = (byte)a;
R = (byte)r;
G = (byte)g;
B = (byte)b;
}
public Color( int r, int g, int b ) {
A = 255;
R = (byte)r;
G = (byte)g;
B = (byte)b;
}
public override bool Equals( object obj ) {
return ( obj is Color ) && Equals( (Color)obj );
}
public bool Equals( Color other ) {
return A == other.A && R == other.R && G == other.G && B == other.B;
}
public override int GetHashCode() {
return A << 24 | R << 16 | G << 8 | B;
}
public static bool operator == ( Color left, Color right ) {
return left.Equals( right );
}
public static bool operator != ( Color left, Color right ) {
return !left.Equals( right );
}
public override string ToString() {
return R + ", " + G + ", " + B + " : " + A;
}
}
}
#endif