Page 1 of 1

Projectile2D

Posted: Mon Mar 28, 2011 5:02 pm
by Jonah Bron
Hello, world!

Just for fun, I whipped together a couple of little classes to simulate a projectile's path in a 2D universe. All it does now is take an initial velocity, a gravity, and a resistance constant. Here's Point2D:

Code: Select all

<?php

namespace D;

/**
 * Point2D
 *
 * Holds a position on a 2-dimensional plane
 *
 * @author Jonah Dahlquist <jonah[at]nucleussystems[dot]com>
 */
class Point2D
{
	/**
	 * The x dimension position
	 *
	 * @var double $x
	 */
	public $x = 0;
	
	/**
	 * The y dimension position
	 *
	 * @var double $y
	 */
	public $y = 0;
	
	/**
	 * Create a new Point2D
	 *
	 * @param double $x X dimension (optional, default 0)
	 * @param double $y Y dimension (optional, default 0)
	 */
	public function __construct($x = 0, $y = 0)
	{
		$this->x = $x;
		$this->y = $y;
	}
	
	/**
	 * Puts this Point object into a human-readable format
	 *
	 * @return string
	 */
	public function __toString()
	{
		return '{ x: ' . $this->x . ', y: ' . $this->y . ' }';
	}
}
And this is Projectile2D:

Code: Select all

<?php

namespace D;

/**
 * Projectile2D
 * 
 * Simulates a projectile launched from the origin (0, 0) with a given initial
 * velocity, resistance, and universal accelerative force (e.g. gravity).
 *
 * @author Jonah Dahlquist <jonah[at]nucleussystems[dot]com>
 */
class Projectile2D
{
	/**
	 * Keeps the inital velocity passed through constructor
	 *
	 * @var Point $initialVelocity
	 */
	protected $initialVelocity = null;
	
	/**
	 * Holds the simulations current velocity
	 *
	 * @var Point $velocity
	 */
	protected $velocity = null;
	
	/**
	 * Holds the projectile's current x & y coordinates
	 *
	 * @var Point $position
	 */
	protected $position = null;
	
	/**
	 * Contains the universal force in x & y direction.  For example,
	 * Jb_Point(0, -1) would accelerate the projectile downward at one foot per
	 * second per second.
	 *
	 * @var Point $gravity
	 */
	protected $gravity = null;
	
	/**
	 * Contains the resistance constant.  This constant is multiplied by the
	 * speed during simulation per-frame to calculate new speed.
	 *
	 * @var double $resistance
	 */
	protected $resistance = null;
	
	/**
	 * Creates a new Projectile2D.
	 *
	 * @param Point $initalVelocity Initial velocity of projectile
	 * @param Point $gravity Universal force
	 * @param double $resistance Resistance (optional, default none)
	 */
	public function  __construct(Point2D $initialVelocity, Point2D $gravity, $resistance = 1)
	{
		$this->initialVelocity = $initialVelocity;
		$this->reset();
		$this->gravity = $gravity;
		$this->resistance = doubleval($resistance);
	}
	
	/**
	 * Runs the simulation a given number of frames
	 *
	 * @param int $frames
	 * @return void
	 */
	public function run($frames)
	{
		while ($frames > 0) {
			$frames--;
			$this->affectVelocityWithGravity();
			$this->affectVelocityWithResistance();
			$this->affectPositionWithVelocity();
		}
	}
	
	/**
	 * Resets the simulation to the origin and initial velocity
	 *
	 * @return void
	 */
	public function reset()
	{
		$this->position = new Point2D();
		$this->velocity = clone $this->initialVelocity;
	}
	
	/**
	 * Gets the projectile's current velocity
	 *
	 * @return Point
	 */
	public function getVelocity()
	{
		return clone $this->velocity;
	}
	
	/**
	 * Gets the projectile's current position
	 *
	 * @return Point
	 */
	public function getPosition()
	{
		return clone $this->position;
	}
	
	/**
	 * Modifies the velocity based on the universal force
	 *
	 * @return void
	 */
	protected function affectVelocityWithGravity()
	{
		$this->velocity->x += $this->gravity->x;
		$this->velocity->y += $this->gravity->y;
	}
	
	/**
	 * Modifies the velocity based on the resistance constant
	 *
	 * @return void
	 */
	protected function affectVelocityWithResistance()
	{
		$this->velocity->x *= $this->resistance;
		$this->velocity->y *= $this->resistance;
	}
	
	/**
	 * Modifies the position based on the velocity
	 *
	 * @return void
	 */
	protected function affectPositionWithVelocity()
	{
		$this->position->x += $this->velocity->x;
		$this->position->y += $this->velocity->y;
	}
}
Pretty simple stuff. Here's an example use:

Code: Select all

<pre>

<?php

require 'D/Projectile2D.php';
require 'D/Point2D.php';

namespace D;

$gun = new Projectile2D(new Point2D(0.5, 1.2), new Point2D(0, -0.03), 0.98);

$positions = array();

for ($i = 0; $i < 200; $i++) {
	$positions[] = $gun->getPosition();
	$gun->run(1);
}

for ($i = 20; $i >= -20; $i--) {
	for ($j = -75; $j < 75; $j++) {
		$found = false;
		if ($i == 0) {
			echo '_';
			continue;
		}
		foreach ($positions as $position) {
			if (round($position->x) == $j && round($position->y) == $i) {
				$found = true;
				break;
			}
		}
		echo $found ? '@' : ' ';
	}
	echo PHP_EOL;
}

?>

</pre>
That will draw a lovely little ASCII graph of the projectile's trajectory.

Seems like this could be useful for graphing of some kind, but that's the only application I can think of. Do you know of any uses for this, or things that could be added to make it more useful?