what I basically gonna do it:
pressing a button spawns (clone) an object to the screen.
I wanna drag it with the mouse into place.
the scene is in 2d view (top view camera) but the objects are 3d.
they can be 2d if it makes things easier.
so far, I have only come by solutions like raycasting from both object and the camera and calculating intersection point.
is there a simpler way?
if not
how should I modify the “movePlayerTo” so the object will simply set position to target pos rather than moving towards it (chance, basically being placed on the same position as the cursor)
That sounds about right. Can’t think of a simpler way TBH.
A VERY quick hack is to increase the speed to something VERY high. The proper way is remove the code in the update function and change the content of the movePlayerTo function to set the position of player entity.
Well, I think dragging will be much easier, since you basically just position the object under the mouse cursor in the game world.
Something like this will do the trick, updated the point and click script (only mouse input):
var PointAndClick = pc.createScript('pointAndClick');
PointAndClick.attributes.add('cameraEntity', {type: 'entity', title: 'Camera Entity'});
PointAndClick.attributes.add('playerEntity', {type: 'entity', title: 'Player Entity'});
PointAndClick.attributes.add('playerSpeed', {type: 'number', default: 0, title: 'Player Speed'});
// initialize code called once per entity
PointAndClick.prototype.initialize = function() {
this.groundShape = new pc.BoundingBox(new pc.Vec3(0, 0, 0), new pc.Vec3(4, 0.001, 4));
this.direction = new pc.Vec3();
this.distanceToTravel = 0;
this.targetPosition = new pc.Vec3();
// Register the mouse down and touch start event so we know when the user has clicked
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
this.app.mouse.on(pc.EVENT_MOUSEUP, this.onMouseUp, this);
};
PointAndClick.newPosition = new pc.Vec3();
// update code called every frame
PointAndClick.prototype.update = function(dt) {
this.playerEntity.setPosition(this.targetPosition);
};
PointAndClick.prototype.movePlayerTo = function (worldPosition) {
this.targetPosition.copy(worldPosition);
this.targetPosition.y = this.playerEntity.getPosition().y;
};
PointAndClick.prototype.onMouseDown = function(event) {
if (event.button == pc.MOUSEBUTTON_LEFT) {
this.dragging = true;
}
};
PointAndClick.prototype.onMouseMove = function(event) {
if (this.dragging === true) {
this.doRayCast(event);
}
};
PointAndClick.prototype.onMouseUp = function(event) {
if (event.button == pc.MOUSEBUTTON_LEFT) {
this.dragging = false;
}
};
PointAndClick.ray = new pc.Ray();
PointAndClick.hitPosition = new pc.Vec3();
PointAndClick.prototype.doRayCast = function (screenPosition) {
// Initialise the ray and work out the direction of the ray from the a screen position
var ray = PointAndClick.ray;
var hitPosition = PointAndClick.hitPosition;
this.cameraEntity.camera.screenToWorld(screenPosition.x, screenPosition.y, this.cameraEntity.camera.farClip, ray.direction);
ray.origin.copy(this.cameraEntity.getPosition());
ray.direction.sub(ray.origin).normalize();
// Test the ray against the ground
var result = this.groundShape.intersectsRay(ray, hitPosition);
if (result) {
this.movePlayerTo(hitPosition);
}
};
now, if I have more than 1 object i want that if the ray hits one of them they become the ‘player entity’ until released.
I see that in order to detect the intersection of the floor, you saved it as a variable.
can I be acquired via investigation of any kind of “out hit”? is there an entity return result to raycasting?
and how do I raycast without intersectsRay when I don’t have a predefined object?
oh neat
now i have something interesting here
i did use the tutorial and got this
var PickerRaycast = pc.createScript('pickerRaycast');
PointAndClick.attributes.add('pickedEntity', {type: 'entity', title: 'picked Entity'});
// initialize code called once per entity
PickerRaycast.prototype.initialize = function() {
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onSelect, this);
};
PickerRaycast.prototype.onSelect = function (e) {
var from = this.entity.camera.screenToWorld(e.x, e.y, this.entity.camera.nearClip);
var to = this.entity.camera.screenToWorld(e.x, e.y, this.entity.camera.farClip);
this.pickedEntity = this.app.systems.rigidbody.raycastFirst(from, to);
// pickedEntity.script.pulse.pulse();
};
simply instead of invoking pulse, I aimed to save it ina variable which I wanna access from another script.
on that other script (on init this time, not the camera
I did
var PointAndClick = pc.createScript('pointAndClick');
PointAndClick.attributes.add('currEntity', {type: 'entity', title: 'Current Entity'});
PointAndClick.attributes.add('cameraEntity', {type: 'entity', title: 'Camera Entity'});
// initialize code called once per entity
PointAndClick.prototype.initialize = function() {
var picker = this.cameraEntity;
console.log("now selected " +this.picker.name);
};
and aim to assign to currentEntity the saved var on cameraEntity.
however, although I assigned the camera to the variable in the inspector, I get that cameraEntity is undefined, as well as picker;
I found the project on your profile. There are a number of issues with the scripts in that it was using variables declared in the functions and not on the this object.
thanks. could you please mark with //whatever you want
the places you changed so i won’t need to do a long match catch?
cause i see no change and the same errors persist…
1 of the changes i see you’ve made was replacing the
i have 1 think i didn’t understand so far and its the
this.groundShape = new pc.BoundingBox(new pc.Vec3(0, 0, 0), new pc.Vec3(4, 0.001, 4));
why do I have to create an imaginary bounding box to intersect with and cannot use a plane model in the scene?
is it possible to use a collision property or anything?
var PointAndClick = pc.createScript('pointAndClick');
PointAndClick.attributes.add('currEntity', {type: 'entity', title: 'Current Entity'});
PointAndClick.attributes.add('cameraEntity', {type: 'entity', title: 'Camera Entity'});
//PointAndClick.attributes.add('Speed', {type: 'number', default: 10, title: 'Track Speed'});
// ray variables
PointAndClick.ray = new pc.Ray();
PointAndClick.hitPosition = new pc.Vec3();
//dragiing variable
PointAndClick.dragging = false;
// initialize code called once per entity
PointAndClick.prototype.initialize = function() {
this.picker = this.cameraEntity;
console.log("now selected " +this.picker.name);
this.groundShape = new pc.BoundingBox(new pc.Vec3(0, 0, 0), new pc.Vec3(4, 0.001, 4));
// this.direction = new pc.Vec3();
// this.distanceToTravel = 0;
this.targetPosition = new pc.Vec3();
// Register the mouse down and touch start event so we know when the user has clicked
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
this.app.mouse.on(pc.EVENT_MOUSEUP, this.onMouseUp, this);
};
PointAndClick.newPosition = new pc.Vec3();
// update code called every frame
PointAndClick.prototype.update = function(dt) {
if(this.cameraEntity.script.pickerRaycast.pickedEntity)
{
if (!this.currEntity || this.currEntity !=this.cameraEntity.script.pickerRaycast.pickedEntity)
{
this.currEntity = this.cameraEntity.script.pickerRaycast.pickedEntity;
console.log("now selected " +this.currEntity.name);
}
if(this.dragging)
this.currEntity.setPosition(this.targetPosition);
}
};
PointAndClick.prototype.onMouseDown = function(event) {
if (event.button == pc.MOUSEBUTTON_LEFT) {
this.dragging = true;
}
};
PointAndClick.prototype.onMouseMove = function(event) {
if (this.dragging === true) {
this.doRayCast(event);
}
};
PointAndClick.prototype.onMouseUp = function(event) {
if (event.button == pc.MOUSEBUTTON_LEFT) {
this.dragging = false;
}
};
PointAndClick.prototype.doRayCast = function (screenPosition) {
// Initialise the ray and work out the direction of the ray from the a screen position
var ray = PointAndClick.ray;
var hitPosition = PointAndClick.hitPosition;
this.cameraEntity.camera.screenToWorld(screenPosition.x, screenPosition.y, this.cameraEntity.camera.farClip, ray.direction);
ray.origin.copy(this.cameraEntity.getPosition());
ray.direction.sub(ray.origin).normalize();
// Test the ray against the ground
var result = this.groundShape.intersectsRay(ray, hitPosition);
if (result) {
this.moveEntityTo(hitPosition);
}
};
PointAndClick.prototype.moveEntityTo = function (worldPosition) {
if(this.currEntity)
{
this.targetPosition.copy(worldPosition);
this.targetPosition.y = this.currEntity.getPosition().y;
}
};
to drag around objects that were selected by another script (‘PickerRaycast’);
while it drags really well, if I don’t touch it at the center, rather than ‘jumping’ to the center of the cursor, it jumps way way further for a frame or 2 and only then repositions itself under my cursor.
why is this jump? and how can I prevent it? bug?
the issue is not consistent and happens without an identifiable pattern I could figure.