Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First shot at extracting IntVector3 from Vector3 #96

Closed
wants to merge 1 commit into from

Conversation

dktapps
Copy link
Member

@dktapps dktapps commented Dec 3, 2024

I've stalled to do this for years because I can't quite figure out how to make the API work nice.

I thought if I just ploughed ahead with it it might become clearer. I'm not happy with what I came up with, so I'm hoping to start some debate about this.

The IntVector3 API differs from Vector3 in the following:

  • Everything that accepted/returned Vector3 instead works with IntVector3
  • The following APIs are removed:
    • getX, getY, getZ (redundant)
    • getFloorX, getFloorY, getFloorZ (useless)
    • ceil, floor, round (useless)
    • divide (would return float vector)
    • normalize (would return float vector)
    • getIntermediateWith*Value (would return float vector)

Problems

I don't want to couple IntVector3 and Vector3, but I don't see a choice if we want to maximize usability.

The following functions don't care whether their inputs are int or float vectors, but implementing them on both sides requires duplicating code:

  • getIntermediateWith*Value (also must return float vector3)
  • normalize (must return float vector3)
  • divide (must return float vector3)
  • minComponents, maxComponents, sum do not care about input types, but to get separation of types requires 2 functions
  • dot, cross don't care about left or right types
  • distance, distanceSquared don't care about left or right types

Basically all float vector ops would accept int vectors

Big question: Where do we draw the line and tell people to just make a FloatVector3 from an IntVector3? If we don't want to force them to do that, how do we design the API?

My current approach is to delete anything from IntVector3 that would involve floats
Probably will make FloatVector3 accept FloatVector3|IntVector3, but this creates symmetry issues (e.g. $v3f->add($v3i) would be OK but $v3i->add(v3f) would not, despite both being mathematically valid)

@dktapps dktapps requested a review from a team as a code owner December 3, 2024 20:19
@Dhaiven
Copy link

Dhaiven commented Dec 3, 2024

Maybe add a Vector3 class with static method like add, substract... Each method can have float|int for each position parameters and in function we choose if we take FloatVector3 or IntVector3
Exemple:

public static function add(FloatVector3|IntVector3, float|int $x, float|int $y, float|int $z): FloatVector3|IntVector3 {
  //If x, y & z are int return a NEW IntVector3 else FloatVector3
}

FloatVector3 & IntVector3 would just be a class like:

readonly class IntVector3{
	public function __construct(
		public int $x,
		public int $y,
		public int $z
	){}
}

@dktapps
Copy link
Member Author

dktapps commented Dec 3, 2024

Yeah, I did consider that. Main reason I don't like it is because it would make chained operations a lot more verbose.

$this->motion = $this->motion->addVector($vector->normalize()->multiply($d));

vs

$this->motion = Vector3::addVector($this->motion, Vector3::multiply(Vector3::normalize($vector), $d));

@dktapps
Copy link
Member Author

dktapps commented Dec 3, 2024

Also looked into using PHPStan generics, but generics of primitive types are not well supported.

@Dhaiven
Copy link

Dhaiven commented Dec 4, 2024

Maybe make an in-between.
Put the functions that require another vector as parameters (like addVector) in static in the Vector3 class and the others (like normalize, add...) in the IntVector3 class.

Syntax will be:

$this->motion = Vector3::addVector($this->motion, $vector->normalize()->multiply($d));

(I think replace Vector3::addVector by Vector3::sum is more correct)

@Dhaiven
Copy link

Dhaiven commented Dec 4, 2024

This system can work with Vector2 too (if we want implements operation between them later):

public static function sum(IntVector3|FloatVector3|Vector2 $vector1, IntVector3|FloatVector3|Vector2 $vector2): IntVector3|FloatVector3|Vector2

@dktapps
Copy link
Member Author

dktapps commented Dec 4, 2024

This system can work with Vector2 too (if we want implements operation between them later):

public static function sum(IntVector3|FloatVector3|Vector2 $vector1, IntVector3|FloatVector3|Vector2 $vector2): IntVector3|FloatVector3|Vector2

God no, that looks awful

@dktapps
Copy link
Member Author

dktapps commented Dec 4, 2024

There's also no proper way to add a Vector2 to a Vector3, since we can't know which coordinates the caller wanted adding together.

@Dhaiven
Copy link

Dhaiven commented Dec 4, 2024

Ok for Vector2, but the idea of separating functions that require a vector and not is problematic ?
I don't see a better approach

@dktapps
Copy link
Member Author

dktapps commented Dec 4, 2024

Following internals discussions it became apparent that the only need for an int vector is for block positions so it makes more sense to specialize it.

@dktapps dktapps closed this Dec 9, 2024
@dktapps dktapps deleted the int-vector3 branch December 9, 2024 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants