Added base physics

This commit is contained in:
Shoghi Cervantes 2014-05-25 12:31:00 +02:00
parent ec055fd8d1
commit 4f2856dc09
9 changed files with 360 additions and 25 deletions

View File

@ -20,6 +20,7 @@
*/
namespace pocketmine\block;
use pocketmine\math\AxisAlignedBB;
/**
@ -41,4 +42,8 @@ class Air extends Transparent{
}
public function collidesWithBB(AxisAlignedBB $bb, &$list = array()){
}
}

View File

@ -24,8 +24,11 @@
*/
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\level\Position;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\Player;
@ -710,6 +713,26 @@ abstract class Block extends Position implements Metadatable{
*/
abstract function onBreak(Item $item);
/**
* Checks for collision against an AxisAlignedBB
*
* @param AxisAlignedBB $bb
* @param Block[] $list
*/
public function collidesWithBB(AxisAlignedBB $bb, &$list = array()){
$bb2 = new AxisAlignedBB(
$this->x,
$this->y,
$this->z,
$this->x + 1,
$this->y + 1,
$this->z + 1
);
if($bb2->intersectsWith($bb)){
$list[] = $bb2;
}
}
/**
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
*

View File

@ -21,8 +21,11 @@
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\level\Level;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\Player;
use pocketmine\Server;

View File

@ -27,6 +27,7 @@ use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Short;
use pocketmine\nbt\tag\String;
use pocketmine\network\protocol\AddItemEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player;
class DroppedItem extends Entity{
@ -38,6 +39,12 @@ class DroppedItem extends Entity{
/** @var Item */
protected $item;
public $width = 0.25;
public $length = 0.25;
public $height = 0.25;
protected $gravity = 0.04;
protected $drag = 0.02;
protected function initEntity(){
//TODO: upgrade old numeric entity ids
$this->namedtag->id = new String("id", "Item");
@ -156,6 +163,13 @@ class DroppedItem extends Entity{
$pk->metadata = $this->getData();
$player->dataPacket($pk);
$pk = new SetEntityMotionPacket;
$pk->eid = $this->getID();
$pk->speedX = $this->motionX;
$pk->speedY = $this->motionY;
$pk->speedZ = $this->motionZ;
$player->dataPacket($pk);
parent::spawnTo($player);
}
}

View File

@ -49,6 +49,7 @@ use pocketmine\network\protocol\SetTimePacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use pocketmine\Server;
use pocketmine\block\Block;
abstract class Entity extends Position implements Metadatable{
public static $entityCount = 1;
@ -83,6 +84,7 @@ abstract class Entity extends Position implements Metadatable{
public $lastYaw;
public $lastPitch;
/** @var AxisAlignedBB */
public $boundingBox;
public $onGround;
public $positionChanged;
@ -105,6 +107,8 @@ abstract class Entity extends Position implements Metadatable{
public $airTicks;
public $namedtag;
protected $isColliding = false;
protected $inWater;
public $noDamageTicks;
private $justCreated;
@ -113,6 +117,9 @@ abstract class Entity extends Position implements Metadatable{
protected $spawnTime;
protected $gravity;
protected $drag;
/** @var Server */
protected $server;
@ -173,6 +180,7 @@ abstract class Entity extends Position implements Metadatable{
$this->lastUpdate = $this->spawnTime = microtime(true);
$this->justCreated = false;
$this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this));
$this->scheduleUpdate();
}
public function saveNBT(){
@ -268,8 +276,19 @@ abstract class Entity extends Position implements Metadatable{
return false;
}
$hasUpdate = false;
$timeNow = microtime(true);
$this->ticksLived += ($timeNow - $this->lastUpdate) * 20;
$ticksOffset = min(20, max(1, floor(($timeNow - $this->lastUpdate) * 20))); //Simulate min one tic and max 20
$this->ticksLived += $ticksOffset;
if(!($this instanceof Player)){
for($tick = 0; $tick < $ticksOffset; ++$tick){
$this->move($this->motionX, $this->motionY, $this->motionZ);
if($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0){
break;
}
}
}
if($this->handleWaterMovement()){
$this->fallDistance = 0;
@ -345,7 +364,7 @@ abstract class Entity extends Position implements Metadatable{
$this->lastUpdate = $timeNow;
return false;
return !($this instanceof Player) and ($this->motionX != 0 or $this->motionY == 0 or $this->motionZ == 0 or $hasUpdate);
}
public final function scheduleUpdate(){
@ -469,12 +488,242 @@ abstract class Entity extends Position implements Metadatable{
return new Position($this->x, $this->y, $this->z, $this->level);
}
public function move(Vector3 $displacement){
if($displacement->x == 0 and $displacement->y == 0 and $displacement->z == 0){
public function collision(){
$this->isColliding = true;
$this->fallDistance = 0;
}
/**
* Returns the entities near the current one inside the AxisAlignedBB
*
* @param AxisAlignedBB $bb
*
* @return Entity[]
*/
public function getNearbyEntities(AxisAlignedBB $bb){
$nearby = [];
$minX = ($bb->minX - 2) >> 4;
$maxX = ($bb->maxX + 2) >> 4;
$minZ = ($bb->minZ - 2) >> 4;
$maxZ = ($bb->maxX + 2) >> 4;
for($x = $minX; $x <= $maxX; ++$x){
for($z = $minZ; $z <= $maxZ; ++$z){
if($this->getLevel()->isChunkLoaded($x, $z)){
foreach($this->getLevel()->getChunkEntities($x, $z) as $ent){
if($ent !== $this and $ent->boundingBox->intersectsWith($this->boundingBox)){
$nearby[] = $ent;
}
}
}
}
}
return $nearby;
}
public function move($dx, $dy, $dz){
//$collision = [];
//$this->checkBlockCollision($collision);
if($dx == 0 and $dz == 0 and $dy == 0){
return;
}
$this->scheduleUpdate();
$ox = $this->x;
$oy = $this->y;
$oz = $this->z;
if($this->isColliding){ //With an entity
$this->isColliding = false;
$dx *= 0.25;
$dy *= 0.05;
$dz *= 0.25;
$this->motionX = 0;
$this->motionY = 0;
$this->motionZ = 0;
}
$movX = $dx;
$movY = $dy;
$movZ = $dz;
/*$sneakFlag = $this->onGround and $this instanceof Player;
if($sneakFlag){
for($mov = 0.05; $dx != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
if($dx < $mov and $dx >= -$mov){
$dx = 0;
}elseif($dx > 0){
$dx -= $mov;
}else{
$dx += $mov;
}
}
for(; $dz != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
if($dz < $mov and $dz >= -$mov){
$dz = 0;
}elseif($dz > 0){
$dz -= $mov;
}else{
$dz += $mov;
}
}
//TODO: big messy loop
}*/
if(count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, $dy, 0))) > 0){
$dy = 0;
$dx = 0;
$dz = 0;
}
$fallingFlag = $this->onGround or ($dy != $movY and $movY < 0);
if($dx != 0){
if(count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, 0, 0))) > 0){
$dy = 0;
$dx = 0;
$dz = 0;
}
}
if($dz != 0){
if(count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, 0, $dz))) > 0){
$dy = 0;
$dx = 0;
$dz = 0;
}
}
if($movX != $dx or $movZ != $dz or $fallingFlag){
$cx = $dx;
$cy = $dy;
$cz = $dz;
$dx = $movX;
$dy = 0.05;
$dz = $movZ;
$oldBB = clone $this->boundingBox;
$list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ));
foreach($list as $bb){
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
}
$this->boundingBox->addCoord(0, $dy, 0);
if($movY != $dy){
$dx = 0;
$dy = 0;
$dz = 0;
}
foreach($list as $bb){
$dx = $bb->calculateXOffset($this->boundingBox, $dx);
}
$this->boundingBox->addCoord($dx, 0, 0);
if($movX != $dx){
$dx = 0;
$dy = 0;
$dz = 0;
}
foreach($list as $bb){
$dz = $bb->calculateZOffset($this->boundingBox, $dz);
}
$this->boundingBox->addCoord(0, 0, $dz);
if($movZ != $dz){
$dx = 0;
$dy = 0;
$dz = 0;
}
if($movY != $dy){
$dy = -0.05;
foreach($list as $bb){
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
}
$this->boundingBox->addCoord(0, $dy, 0);
}
if($cx * $cx + $cz * $cz > $dx * $dx + $dz * $dz){
$dx = $cx;
$dy = $cy;
$dz = $cz;
$this->boundingBox->setBB($oldBB);
}
}
$this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
$this->y = $this->boundingBox->minY + $this->height;
$this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;
$this->onGround = $movY != $dy and $movY < 0;
$this->updateFallState($dy, $this->onGround);
if($movX != $dx){
$this->motionX = 0;
}else{
$this->motionX -= $this->motionX * $this->drag;
}
if($movY != $dy){
$this->motionY = 0;
}else{
$this->motionY -= $this->motionY * $this->drag;
}
if($movZ != $dz){
$this->motionZ = 0;
}else{
$this->motionY -= $this->motionY * $this->drag;
}
//$this->boundingBox->addCoord($dx, $dy, $dz);
//$this->x += $dx;
//$this->y += $dy;
//$this->z += $dz;
$cx = $this->x - $ox;
$cy = $this->y - $oy;
$cz = $this->z - $oz;
//TODO: vehicle collision events (first we need to spawn them!)
}
/**
* @param Block[] $list
*
* @return Block[]
*/
protected function checkBlockCollision(&$list = array()){
$minX = floor($this->boundingBox->minX + 0.001);
$minY = floor($this->boundingBox->minY + 0.001);
$minZ = floor($this->boundingBox->minZ + 0.001);
$maxX = floor($this->boundingBox->maxX + 0.001);
$maxY = floor($this->boundingBox->maxY + 0.001);
$maxZ = floor($this->boundingBox->maxZ + 0.001);
for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){
$this->getLevel()->getBlock(new Vector3($x, $y, $z))->collidesWithBB($this->boundingBox, $list);
}
}
}
return $list;
}
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){

View File

@ -42,6 +42,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/** @var PlayerInventory */
protected $inventory;
public $width = 0.6;
public $length = 0.6;
public $height = 1.8;
public function getInventory(){
return $this->inventory;
}
@ -68,9 +72,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
}
}
$this->height = 1.8; //Or 1.62?
$this->width = 0.6;
parent::initEntity();
}

View File

@ -23,6 +23,10 @@ namespace pocketmine\entity;
abstract class Living extends Entity implements Damageable{
protected $gravity = 0.08;
protected $drag = 0.02;
protected function initEntity(){
}

View File

@ -35,6 +35,7 @@ use pocketmine\item\Item;
use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\generator\Flat;
use pocketmine\level\generator\Generator;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector2;
use pocketmine\math\Vector3 as Vector3;
use pocketmine\nbt\NBT;
@ -323,7 +324,7 @@ class Level{
//Do chunk updates
while($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){
$block = $this->getBlockRaw($this->updateQueue->extract()["data"]);
$block = $this->getBlock($this->updateQueue->extract()["data"]);
$block->onUpdate(self::BLOCK_UPDATE_SCHEDULED);
}
@ -332,7 +333,7 @@ class Level{
for($Y = 0; $Y < 8; ++$Y){
if(!$this->level->isMiniChunkEmpty($X, $Z, $Y)){
for($i = 0; $i < 3; ++$i){
$block = $this->getBlockRaw(new Vector3(($X << 4) + mt_rand(0, 15), ($Y << 4) + mt_rand(0, 15), ($Z << 4) + mt_rand(0, 15)));
$block = $this->getBlock(new Vector3(($X << 4) + mt_rand(0, 15), ($Y << 4) + mt_rand(0, 15), ($Z << 4) + mt_rand(0, 15)));
if($block instanceof Block){
if($block->onUpdate(self::BLOCK_UPDATE_RANDOM) === self::BLOCK_UPDATE_NORMAL){
$this->updateAround($block, self::BLOCK_UPDATE_NORMAL);
@ -510,6 +511,39 @@ class Level{
return Block::get($b[0], $b[1], new Position($pos->x, $pos->y, $pos->z, $this));
}
/**
* @param Entity $entity
* @param AxisAlignedBB $bb
*
* @return AxisAlignedBB[]
*/
public function getCollisionCubes(Entity $entity, AxisAlignedBB $bb){
$minX = floor($bb->minX);
$minY = floor($bb->minY);
$minZ = floor($bb->minZ);
$maxX = floor($bb->maxX + 1);
$maxY = floor($bb->maxY + 1);
$maxZ = floor($bb->maxZ + 1);
$collides = [];
for($z = $minZ; $z < $maxZ; ++$z){
for($x = $minX; $x < $maxX; ++$x){
if($this->isChunkLoaded($x >> 4, $z >> 4)){
for($y = $minY - 1; $y < $maxY; ++$y){
$this->getBlock(new Vector3($x, $y, $z))->collidesWithBB($bb, $collides);
}
}
}
}
foreach($entity->getNearbyEntities($bb->expand(0.25, 0.25, 0.25)) as $ent){
$collides[] = $ent->boundingBox;
}
return $collides;
}
/**
* @param Vector3 $pos
* @param Block $block
@ -624,7 +658,7 @@ class Level{
//TODO: add random motion with physics
"Motion" => new Enum("Motion", [
new Double("", 0),
new Double("", 0),
new Double("", 0.05),
new Double("", 0)
]),
"Rotation" => new Enum("Rotation", [
@ -991,6 +1025,10 @@ class Level{
return [];
}
public function isChunkLoaded($X, $Z){
return $this->level->isChunkLoaded($X, $Z);
}
/**
* Loads a chunk
*

View File

@ -54,26 +54,25 @@ class AxisAlignedBB{
}
public function addCoord($x, $y, $z){
$vec = clone $this;
if($x < 0){
$vec->minX += $x;
$this->minX += $x;
}elseif($x > 0){
$vec->maxX += $x;
$this->maxX += $x;
}
if($y < 0){
$vec->minY += $y;
$this->minY += $y;
}elseif($y > 0){
$vec->maxY += $y;
$this->maxY += $y;
}
if($z < 0){
$vec->minZ += $z;
$this->minZ += $z;
}elseif($z > 0){
$vec->maxZ += $z;
$this->maxZ += $z;
}
return $vec;
return $this;
}
public function expand($x, $y, $z){
@ -197,14 +196,13 @@ class AxisAlignedBB{
}
public function intersectsWith(AxisAlignedBB $bb){
if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
return false;
}
if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
return false;
if($bb->maxX > $this->minX and $bb->minX < $this->maxX){
if($bb->maxY > $this->minY and $bb->minY < $this->maxY){
return $bb->maxZ > $this->minZ and $bb->minZ < $this->maxZ;
}
}
return $bb->maxZ > $this->minZ and $bb->minZ < $this->maxZ;
return false;
}
public function isVectorInside(Vector3 $vector){