mirror of
https://github.com/solcloud/Counter-Strike.git
synced 2025-02-23 19:32:50 +01:00
Tuning
This commit is contained in:
parent
1c8b72c7b5
commit
580bdc18c2
@ -47,6 +47,8 @@ class Game
|
||||
$this->world = new World($this);
|
||||
$this->score = new Score();
|
||||
$this->properties = $properties;
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
private function initialize(): void
|
||||
@ -71,9 +73,6 @@ class Game
|
||||
$this->tickEvents = [$this->gameOver];
|
||||
return $this->gameOver;
|
||||
}
|
||||
if ($tickId === 0) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$alivePlayers = [0, 0];
|
||||
foreach ($this->players as $player) {
|
||||
|
@ -9,9 +9,9 @@ use cs\Weapon\Knife;
|
||||
|
||||
class HitBox implements Hittable
|
||||
{
|
||||
private int $moneyAward = 0;
|
||||
private bool $playerWasKilled = false;
|
||||
private bool $wasHeadShot = false;
|
||||
private int $moneyAward;
|
||||
private bool $playerWasKilled;
|
||||
private bool $wasHeadShot;
|
||||
|
||||
public function __construct(
|
||||
private Player $player,
|
||||
@ -19,6 +19,7 @@ class HitBox implements Hittable
|
||||
private HitIntersect $geometry
|
||||
)
|
||||
{
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
@ -51,7 +52,7 @@ class HitBox implements Hittable
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO do back hit box based on player and bullet angle
|
||||
// TODO do back hit box based on player and bullet angle, or add HitBoxBack geometry
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -16,24 +16,29 @@ final class Player
|
||||
use PlayerTrait\MovementTrait;
|
||||
use PlayerTrait\InventoryTrait;
|
||||
|
||||
// Better to use even numbers
|
||||
// NOTE: Better to use even numbers for all constants
|
||||
// TODO: migrate to time based values, so we can play on different tick settings, and expand simulation tests, maybe some player setting object
|
||||
public const speedFall = 60;
|
||||
public const speedMove = 50; // TODO: linear movement or ease-in-out?
|
||||
public const speedMove = 50;
|
||||
public const speedJump = 30;
|
||||
public const speedMoveWalk = 40;
|
||||
public const speedMoveCrouch = 30;
|
||||
public const speedJump = 30;
|
||||
public const tickCountJump = 5;
|
||||
public const tickCountCrouch = 10;
|
||||
|
||||
public const headRadius = 30;
|
||||
public const bodyRadius = 44;
|
||||
public const jumpHeight = 150;
|
||||
public const headHeightStand = 190;
|
||||
public const gunHeightStand = self::headHeightStand - self::headRadius;
|
||||
public const headHeightCrouch = 140;
|
||||
public const boxHeightCrouchCover = self::headHeightCrouch + 2;
|
||||
public const obstacleOvercomeHeight = 20;
|
||||
public const playerBoundingRadius = self::bodyRadius;
|
||||
public const fallDamageThreshold = 3 * self::headHeightStand;
|
||||
public const jumpHeight = self::speedJump * self::tickCountJump;
|
||||
public const headRadius = 30;
|
||||
public const bodyRadius = 44;
|
||||
public const boxHeightCrouchCover = self::headHeightCrouch + 2;
|
||||
public const gunHeightStand = self::headHeightStand - self::headRadius;
|
||||
/** @deprecated make it private eventually */
|
||||
public int $playerBoundingRadius = self::playerBoundingRadius;
|
||||
|
||||
public const jumpMovementSlowDown = 1;
|
||||
public const flyingMovementSlowDown = 0.8;
|
||||
|
||||
@ -47,11 +52,10 @@ final class Player
|
||||
/** @var Event[] */
|
||||
private array $events = [];
|
||||
|
||||
private bool $isAttacking = false;
|
||||
private int $health = 100;
|
||||
private int $health;
|
||||
private int $armor = 0;
|
||||
private int $headHeight = self::headHeightStand; // highest player point
|
||||
public int $playerBoundingRadius = self::playerBoundingRadius;
|
||||
private int $headHeight; // highest player point
|
||||
private bool $isAttacking = false;
|
||||
|
||||
// Event IDs, sequence, ascending order priority
|
||||
private int $eventIdPrimary = 0;
|
||||
@ -77,6 +81,11 @@ final class Player
|
||||
|
||||
private function initialize(): void
|
||||
{
|
||||
$this->health = 100;
|
||||
$this->isWalking = false;
|
||||
$this->headHeight = self::headHeightStand;
|
||||
|
||||
$this->events = [];
|
||||
$this->addEvent($this->createMovementEvent(), $this->eventIdMovement);
|
||||
$this->addEvent($this->createGravityEvent(), $this->eventIdGravity);
|
||||
}
|
||||
@ -99,6 +108,11 @@ final class Player
|
||||
$this->isAttacking = false;
|
||||
}
|
||||
|
||||
private function onPlayerDied(): void
|
||||
{
|
||||
$this->armor = 0;
|
||||
}
|
||||
|
||||
private function addEvent(Event $event, int $eventId): void
|
||||
{
|
||||
$this->events[$eventId] = $event;
|
||||
@ -118,7 +132,7 @@ final class Player
|
||||
|
||||
public function suicide(): void
|
||||
{
|
||||
$this->health = 0;
|
||||
$this->lowerHealth($this->health);
|
||||
$this->world->playerDiedToFallDamage($this);
|
||||
}
|
||||
|
||||
@ -175,6 +189,9 @@ final class Player
|
||||
public function lowerHealth(int $healthDamage): void
|
||||
{
|
||||
$this->health -= abs($healthDamage);
|
||||
if ($this->health <= 0) {
|
||||
$this->onPlayerDied();
|
||||
}
|
||||
}
|
||||
|
||||
public function getHealth(): int
|
||||
@ -192,11 +209,6 @@ final class Player
|
||||
$this->resetTickStates();
|
||||
$this->getSight()->reset();
|
||||
$this->inventory->reset($this->isPlayingOnAttackerSide, !$this->isAlive());
|
||||
|
||||
$this->events = [];
|
||||
$this->health = 100;
|
||||
$this->isWalking = false;
|
||||
$this->headHeight = self::headHeightStand;
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
@ -239,7 +251,7 @@ final class Player
|
||||
"heightSight" => $this->getSightHeight(),
|
||||
"heightBody" => $this->getBodyHeight(),
|
||||
"height" => $this->getHeadHeight(),
|
||||
"armor" => 0, //TODO
|
||||
"armor" => $this->armor, //TODO
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,6 @@ use cs\Map\Map;
|
||||
|
||||
class World
|
||||
{
|
||||
private const ATTACKER = 0;
|
||||
private const DEFENDER = 1;
|
||||
private const WALL_X = 0;
|
||||
private const WALL_Z = 1;
|
||||
|
||||
@ -146,7 +144,7 @@ class World
|
||||
throw new GameException("No map is loaded! Cannot spawn players.");
|
||||
}
|
||||
|
||||
$key = ($isAttacker ? self::ATTACKER : self::DEFENDER);
|
||||
$key = (int)$isAttacker;
|
||||
if (isset($this->spawnCandidates[$key])) {
|
||||
$source = $this->spawnCandidates[$key];
|
||||
} else {
|
||||
@ -181,24 +179,26 @@ class World
|
||||
public function calculateHits(Bullet $bullet): array
|
||||
{
|
||||
$hits = [];
|
||||
|
||||
$alreadyHitPlayerIds = $bullet->getPlayerHitIds();
|
||||
$alreadyHitPlayerIds[$bullet->getOriginPlayerId()] = true; // cannot shoot self
|
||||
|
||||
foreach ($this->playersColliders as $playerCollider) {
|
||||
if (isset($alreadyHitPlayerIds[$playerCollider->getPlayerId()])) {
|
||||
continue; // player already hit
|
||||
continue; // player already hit or self
|
||||
}
|
||||
|
||||
$hitBox = $playerCollider->tryHitPlayer($bullet);
|
||||
if ($hitBox) {
|
||||
$player = $hitBox->getPlayer();
|
||||
if ($player) {
|
||||
$bullet->addPlayerIdHit($player->getId());
|
||||
}
|
||||
if ($hitBox->playerWasKilled() && $player) {
|
||||
if (!$hitBox) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hits[] = $hitBox;
|
||||
$player = $hitBox->getPlayer();
|
||||
if ($player) {
|
||||
$bullet->addPlayerIdHit($player->getId());
|
||||
if ($hitBox->playerWasKilled()) {
|
||||
$this->game->playerAttackKilledEvent($player, $bullet, $hitBox->wasHeadShot());
|
||||
}
|
||||
$hits[] = $hitBox;
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,11 +233,12 @@ class World
|
||||
}
|
||||
|
||||
$candidatePlane = $center->to2D('zy')->addX(-$radius);
|
||||
$width = 2 * $radius;
|
||||
foreach (($this->walls[self::WALL_X][$center->x] ?? []) as $wall) {
|
||||
if ($wall->getCeiling() === $center->y) {
|
||||
continue;
|
||||
}
|
||||
if (Collision::planeWithPlane($wall->getPoint2DStart(), $wall->width, $wall->height, $candidatePlane, 2 * $radius, $height)) {
|
||||
if (Collision::planeWithPlane($wall->getPoint2DStart(), $wall->width, $wall->height, $candidatePlane, $width, $height)) {
|
||||
return $wall;
|
||||
}
|
||||
}
|
||||
@ -252,11 +253,12 @@ class World
|
||||
}
|
||||
|
||||
$candidatePlane = $center->to2D('xy')->addX(-$radius);
|
||||
$width = 2 * $radius;
|
||||
foreach (($this->walls[self::WALL_Z][$center->z] ?? []) as $wall) {
|
||||
if ($wall->getCeiling() === $center->y) {
|
||||
continue;
|
||||
}
|
||||
if (Collision::planeWithPlane($wall->getPoint2DStart(), $wall->width, $wall->height, $candidatePlane, 2 * $radius, $height)) {
|
||||
if (Collision::planeWithPlane($wall->getPoint2DStart(), $wall->width, $wall->height, $candidatePlane, $width, $height)) {
|
||||
return $wall;
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ final class AttackEvent
|
||||
foreach ($hits as $hit) {
|
||||
$bullet->lowerDamage($hit->getHitAntiForce());
|
||||
$result->addHit($hit);
|
||||
if ($bullet->isActive()) {
|
||||
if (!$bullet->isActive()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -278,6 +278,9 @@ class Server
|
||||
$this->logger->log($level, $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function saveRequestMetaData(): void
|
||||
{
|
||||
$players = [];
|
||||
@ -293,6 +296,9 @@ class Server
|
||||
], JSON_THROW_ON_ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function storeRequests(string $path = '/tmp/cs.server.req'): void
|
||||
{
|
||||
$this->saveRequestsPath = $path;
|
||||
|
@ -43,6 +43,7 @@ trait AttackTrait
|
||||
$this->isAttacking = true;
|
||||
$origin = $this->getPositionImmutable();
|
||||
$origin->addY($this->getSightHeight());
|
||||
|
||||
return new AttackEvent(
|
||||
$this->world,
|
||||
$origin,
|
||||
|
@ -31,7 +31,7 @@ class RoundTest extends BaseTestCase
|
||||
$game = $this->createGame();
|
||||
$break = false;
|
||||
$game->onEvents(function (array $e) use (&$events, &$break): void {
|
||||
if ($e === [] || $break) {
|
||||
if ($break) {
|
||||
return;
|
||||
}
|
||||
if ($e[0] instanceof GameOverEvent) {
|
||||
|
@ -75,4 +75,14 @@ class HitBoxTest extends BaseTest
|
||||
$this->assertPositionSame(new Point(-10, -8, 67), $sphere->calculateWorldCoordinate($player, new Point(15, -20, 8)));
|
||||
}
|
||||
|
||||
public function testSphereHitBoxIntersect(): void
|
||||
{
|
||||
$sphere = new SphereHitBox(new Point(-45, 12, 32), 38);
|
||||
$player = new Player(1, Color::GREEN, true);
|
||||
|
||||
$this->assertFalse($sphere->intersect($player, new Point(-10, -8, 67)));
|
||||
$player->getSight()->lookHorizontal(20);
|
||||
$this->assertTrue($sphere->intersect($player, new Point(-10, -8, 67)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -63,13 +63,15 @@ class PlayerKillTest extends BaseTestCase
|
||||
$player1->getInventory()->earnMoney(1000);
|
||||
$player1->buyItem(BuyMenuItem::KEVLAR_BODY_AND_HEAD);
|
||||
$this->assertSame(ArmorType::BODY_AND_HEAD, $player1->getArmorType());
|
||||
$player2->setPosition($player1->getPositionImmutable()->addY($player1->getHeadHeight() + 10));
|
||||
$player2Position = $player1->getPositionImmutable()->addY($player1->getHeadHeight() + 10);
|
||||
$player2->setPosition($player2Position);
|
||||
$player2->getSight()->lookAt(0, -90);
|
||||
|
||||
$result = $player2->attack();
|
||||
$this->assertNotNull($result);
|
||||
$gun = $player2->getEquippedItem();
|
||||
$this->assertInstanceOf(PistolUsp::class, $gun);
|
||||
$this->assertSame($player2Position->y + $player2->getSightHeight(), $result->getBullet()->getDistanceTraveled());
|
||||
|
||||
$hits = $result->getHits();
|
||||
$this->assertCount(2, $hits);
|
||||
|
Loading…
x
Reference in New Issue
Block a user