I am currently writing a test program for a collision function, that involves multithreading so I can simultaneously check for collisions and move a skeleton at the same time. Because of this, I had to use shared
objects. The specific objects I was using were declared in a file called "skeleton.d." In a function I wrote for moving the skeletons, it uses operator overloading, which produces the following output:
physics.d(85): Error: none of the `opOpAssign` overloads of `Point` are callable for `j` of type `shared(Point)`
physics.d(87): Error: none of the `opOpAssign` overloads of `Point` are callable for `k.start` of type `shared(Point)`
physics.d(88): Error: none of the `opOpAssign` overloads of `Point` are callable for `k.stop` of type `shared(Point)`
physics.d(90): Error: none of the `opOpAssign` overloads of `Point` are callable for `i.center` of type `shared(Point)`
physics.d(92): Error: none of the `opOpAssign` overloads of `Point` are callable for `tomove.center` of type `shared(Point)`
physics.d(112): Error: none of the `opOpAssign` overloads of `Point` are callable for `k` of type `shared(Point)`
physics.d(114): Error: none of the `opOpAssign` overloads of `Point` are callable for `j.start` of type `shared(Point)`
physics.d(115): Error: none of the `opOpAssign` overloads of `Point` are callable for `j.stop` of type `shared(Point)`
physics.d(117): Error: none of the `opOpAssign` overloads of `Point` are callable for `i.center` of type `shared(Point)`
physics.d(119): Error: none of the `opOpAssign` overloads of `Point` are callable for `ori.center` of type `shared(Point)`
physics.d(120): Error: none of the overloads of `opAssign` are callable using a `shared` object
skeleton.d(81): Candidates are: `skeleton.Skeleton.opAssign(Skeleton rhs)`
skeleton.d(88): `skeleton.Skeleton.opAssign(shared(Skeleton) rhs)`
physics.d(136): Error: mixin `physics.move.__mov__general__!"n"` error instantiating
This is clearly wrong, as type Point
is not the same as type Skeleton
.
For reference, here are the files:
test.d:
import physics;
void main() {
Skeleton cube;
Face[] cubefaces;
cubefaces.length = 1;
cubefaces[0].lines ~= Line([Point(0,0.25,0), Point(0,0.5,0), Point(0,0.75,0)], Point(0,0,0), Point(0,1,0));
cubefaces[0].lines ~= Line([Point(0.25,0,0), Point(0.5,0,0), Point(0.75,0,0)], Point(0,0,0), Point(1,0,0));
cubefaces[0].lines ~= Line([Point(1,0.25,0), Point(1,0.5,0), Point(1,0.75, 0)], Point(1,0,0), Point(1,1,0));
cubefaces[0].lines ~= Line([Point(0.25,1,0), Point(0.5,1,0), Point(0.75,1,0)], Point(0,1,0), Point(1,1,0));
cubefaces[0].center = Point(0.5,0.5,0);
cube.faces = cubefaces.dup;
cube.center = Point(0.5,0.5,0);
auto cube2 = cube;
move(Point(99,0,0), 0, cast(shared(Skeleton))cube, 99);
import std.stdio;
import std.concurrency;
spawn(&test1, cast(shared(Skeleton))cube2, cast(shared(Skeleton))cube);
spawn(&move,Point(-99,0,0), 5, cast(shared(Skeleton))cube, 1);
bool b = receiveOnly!bool;
writeln(b);
}
void test1(shared ref Skeleton cube2, shared ref Skeleton cube) {
import std.concurrency;
if(detectCollision(cast(shared(Skeleton[]))[cube2], cast(shared(Skeleton))cube, real.infinity))
send(ownerTid(), true);
}
skeleton.d:
/*skeleton.d by Ruby The Roobster*/
/*Version 1.0 Release*/
/*Module for representing skeletons in the D Programming Language 2.0*/
/*This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
/** Copyright: 2021, Ruby The Roobster*/
/**Author: Ruby The Roobster, michaeleverestc79@gmail.com*/
/**Date: October 1, 2021*/
/** License: GPL-3.0*/
module skeleton;
/**Struct for representing a point.*/
public struct Point { //Point structure...
///Point.x is the 'x' coordinate of the point.
real x;
///Point.y is the 'y' coordinate of the point.
real y;
///Point.z is the 'z' coordinate of the point.
real z;
this(real x, real y, real z) {
this.x = x;
this.y = y;
this.z = z;
}
void opAssign(Point rhs) {
this.x = rhs.x;
this.y = rhs.y;
this.z = rhs.z;
}
void opAssign(shared Point rhs) {
this.x = rhs.x;
this.y = rhs.y;
this.z = rhs.z;
}
void opOpAssign(string op)(Point rhs) {
mixin("this.x " ~ op ~ "= rhs.x;");
mixin("this.y " ~ op ~ "= rhs.y;");
mixin("this.z " ~ op ~ "= rhs.z;");
}
void opOpAssign(string op)(shared(Point) rhs) {
mixin("this.x " ~ op ~ "= rhs.x;");
mixin("this.y " ~ op ~ "= rhs.y;");
mixin("this.z " ~ op ~ "= rhs.z;");
}
}
/**Struct for representing a face of a skeleton that is made out of lines.*/
public struct Face { //Face(of a 3D shape) structure...
///Face.lines is an array of all the lines that connect to form the face.
Line[] lines;
///Face.center is the center point of the face.
Point center;
void opAssign(Face rhs) {
this.lines.length = rhs.lines.length;
foreach(i;0 .. this.lines.length) {
this.lines[i] = rhs.lines[i];
}
}
void opAssign(shared Face rhs) {
this.lines.length = rhs.lines.length;
foreach(i;0 .. this.lines.length) {
this.lines[i] = rhs.lines[i];
}
}
}
/**Struct for representing a 3D skeleton.*/
public struct Skeleton { //Skeleton of a 3D structure...
///Skeleton.faces is an array of the faces that make up the Skeleton.
Face[] faces;
///Skeleton.center is the center point of the skeleton.
Point center;
void opAssign(Skeleton rhs) {
this.faces.length = rhs.faces.length;
foreach(i;0 .. this.faces.length) {
this.faces[i] = rhs.faces[i];
}
this.center = rhs.center;
}
void opAssign(shared Skeleton rhs) {
this.faces.length = rhs.faces.length;
foreach(i;0 .. this.faces.length) {
this.faces[i] = rhs.faces[i];
}
this.center = rhs.center;
}
}
/**Struct for representing a line composed of at least a starting point and an end point.
*Notes:
*This struct doesn't check to make sure that the line made is an actual line and assumes the user knows what they are doing.
*/
public struct Line { //Line struct...
///Line.mid_points is an array containing all of the points that are neither start nor end points.
Point[] mid_points;
///Line.start is the start point of the line.
Point start;
///Line.end is the end point of the line.
Point stop;
void opAssign(Line rhs) {
this.start = rhs.start;
this.stop = rhs.stop;
this.mid_points.length = rhs.mid_points.length;
foreach(i;0 .. this.mid_points.length) {
this.mid_points[i] = rhs.mid_points[i];
}
}
void opAssign(shared Line rhs) {
this.start = rhs.start;
this.stop = rhs.stop;
this.mid_points.length = rhs.mid_points.length;
foreach(i;0 .. this.mid_points.length) {
this.mid_points[i] = rhs.mid_points[i];
}
}
}
and finally, physiscs.d:
/*physics.d by Ruby The Roobster*/
/*Version 0.35 testing*/
/*Module for basic physics in the D Programming Language 2.0*/
/*This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
/** Copyright: 2021, Ruby The Roobster*/
/**Author: Ruby The Roobster, michaeleverestc79@gmail.com*/
/**Date: October 27, 2021*/
/** License: GPL-3.0*/
module physics;
public import skeleton;
package mixin template __mov__general__(string func)
{
void __mov__general__(real accdec = 0)
{
import core.thread;
Point moveby;
bool b = false;
auto ori = tomove;
debug import std.stdio : writeln;
if(speed > 1 || speed < -1)
{
moveby.x = moveto.x / speed;
moveby.y = moveto.y / speed;
moveby.z = moveto.z / speed;
b = true;
}
else
{
moveby.x = moveto.x * speed;
moveby.y = moveto.y * speed;
moveby.z = moveto.z * speed;
}
while(!((tomove.center.x > moveto.x && moveto.x > 0) ^ (tomove.center.x < moveto.x && moveto.x < 0)))
{
static if(func == "a")
{
speed += accdec;
if(b)
{
moveby.x = moveto.x / speed;
moveby.y = moveto.y / speed;
moveby.z = moveto.z / speed;
}
else
{
moveby.x = moveto.x * speed;
moveby.y = moveto.y * speed;
moveby.z = moveto.z * speed;
}
}
else static if(func == "d")
{
speed -= accdec;
if(b)
{
moveby.x = moveto.x / speed;
moveby.y = moveto.y / speed;
moveby.z = moveto.z / speed;
}
else
{
moveby.x = moveto.x * speed;
moveby.y = moveto.y * speed;
moveby.z = moveto.z * speed;
}
}
foreach(i;tomove.faces)
{
foreach(k;i.lines)
{
foreach(j;k.mid_points)
{
j += moveby;
}
k.start += moveby;
k.stop += moveby;
}
i.center += moveby;
}
tomove.center += moveby;
Thread.sleep(dur!"msecs"(tbf));
static if(func == "a")
{
speed += accdec;
}
else static if(func == "d")
{
speed -= accdec;
}
else
{
}
}
foreach(i;ori.faces)
{
foreach(j;i.lines)
{
foreach(k;j.mid_points)
{
k += moveto;
}
j.start += moveto;
j.stop += moveto;
}
i.center += moveto;
}
ori.center += moveto;
tomove = ori;
}
}
/**
* move moves all the points in a skeleton to a specified point with a specified time gap between moving the points.
* Params:
* moveto = A point specifying the total amount to move along each axis.
* tbf = The time in miliseconds between 'frames'(a frame is one section of moving points before waiting a bit). This gives an illusion of continuous motion.
* tomove = The skeleton being moved.
* speed = The speed at which to move the points.
* Returns:
* none
*/
pragma(inline, true) public void move(Point moveto, uint tbf, ref shared Skeleton tomove, real speed)
{
mixin __mov__general__!"n";
__mov__general__();
}
/**
* accMove moves all the points in a skeleton to a specified point with a specified time gap between movements all while accelerating the speed.
* Params:
* moveto = A point specifying the total amount to move along each axis.
* tbf = The time in miliseconds between 'frames'(a frame is one section of moving points before waiting a bit). This gives an illusion of continuous motion.
* tomove = The skeleton being moved.
* speed = The original speed at which the skeleton moves.
* accdec = The amount to increment the speed by each frame.
*/
pragma(inline, true) public void accMove(Point moveto, uint tbf, shared ref Skeleton tomove, real speed, real accdec = 0)
{
mixin __mov__general__!"a";
__mov__general__(accdec);
}
/**
* decMove moves all the points in a skeleton to a specified point with a specified time gap between movements all while deaccelerating the speed.
* Params:
* moveto = A point specifying the total amount to move along each axis.
* tbf = The time in miliseconds between 'frames'(a frame is one section of moving points before waiting a bit). This gives an illusion of continuous motion.
* tomove = The skeleton being moved.
* speed = The original speed at which the skeleton moves.
* accdec = The amount to decrement the speed by each frame.
*/
pragma(inline) public void decMove(Point moveto, uint tbf, shared ref Skeleton tomove, real speed, real accdec = 0)
{
mixin __mov__general__!"d";
__mov__general__(accdec);
}
public bool detectCollision(shared Skeleton[] towatch, shared Skeleton skele, real time = 0)
in {
auto a = cast(ulong)time;
assert(a == time || time == real.infinity,"Parameter time must always be a whole number or infinity!");
}
do {
mixin find!(["x", "y", "z"]);
import std.datetime.stopwatch;
auto sw = StopWatch(AutoStart.no);
sw.start();
scope(exit) sw.stop();
while(sw.peek.total!"msecs" <= time || time == real.inf)
{
foreach(i;towatch)
{
foreach(j;i.faces)
{
foreach(k;j.lines)
{
foreach(l;k.mid_points)
{
foreach(m;skele.faces)
{
foreach(n;m.lines)
{
for(uint o; o < n.mid_points.length+1; o++)
{
if(switcho(l))
return true;
if(switcho(k.start))
return true;
if(switcho(k.stop))
return true;
}
}
}
}
}
}
}
}
return false;
}
package mixin template find(string[] tofind)
{
static foreach(i; tofind) {
mixin("real high" ~ i ~ ";");
mixin("real low" ~ i ~ ";");
}
void find(Point[2] tof)
{
static foreach(i; tofind)
{
mixin("high" ~ i ~ " = tof[0]." ~ i ~ " >= tof[1]." ~ i ~ " ? tof[0]." ~ i ~ " : tof[1]." ~ i ~ ";");
mixin("low" ~ i ~ " = tof[0]." ~ i ~ " <= tof[1]." ~ i ~ " ? tof[0]." ~ i ~ " : tof[1]." ~ i ~ ";");
}
}
}
package pragma(inline, true) bool switcho(Point toswitch)
{
switch(o)
{
default:
if(o == n.mid_points.length)
{
find([n.mid_points[o-1], n.stop]);
}
else
{
find([n.mid_points[o-1], n.mid_points[o]]);
}
if(toswitch.x <= highx && toswitch.x >= lowx && toswitch.y <= highy && toswitch.y >= lowy && toswitch.z <= highz && toswitch.z >= lowz)
{
return true;
}
break;
case 0:
find([n.mid_points.start, n.mid_points[o]]);
if(toswitch.x <= highx && toswitch.x >= lowx && toswitch.y <= highy && toswitch.y >= lowy && toswitch.z <= highz && toswitch.z >= lowz)
{
return true;
}
}
}
Can anyone explain why it can't find the correct function? Thanks in advance.