オブジェクトに触れたら処理するスクリプトを作成
前回はクリックしてPlayerを移動させるまでができました。
次は移動させた先に、当たり判定を持ったオブジェクトがあるとイベントを処理させ、テキスト情報を載せたモーダルが表示されるものを作ります。
まずは当たり判定を持ったオブジェクトを作ります。
空のEntity「TriggerObject」を作成し、入れ子にPrimitiveなBoxを追加します。
Boxには当たり判定のため、CollisionとRigidBodyを追加。
TriggerObjectは動く必要がないので、RigidBodyはType: Static にします。
Materialも設定すると見分けがつきやすくなるのでお好みで設定します。
次はスクリプトを設定します。
「triggerCollision.js」を作成して、Boxに追加します。
設定ができたら、以下のスクリプトを「triggerCollision.js」にコピペします。
var TriggerCollision = pc.createScript('triggerCollision');
TriggerCollision.prototype.initialize = function() {
this.entity.collision.on('collisionstart', this.onTriggerEnter, this); // Collisionの範囲にCollisionが入ったら処理
this.entity.collision.on('collisionend', this.onTriggerLeave, this); // Collisionの範囲から外へ出たら処理
};
TriggerCollision.prototype.onTriggerEnter = function(result) {
console.log("Collision Enter");
};
TriggerCollision.prototype.onTriggerLeave = function(result) {
console.log("Collision Leave");
};
Playerにも当たり判定が必要になるので、PlayerのBoxにもCollisionとRigidBodyを設定します。
Playerは移動するので、RigidBodyのTypeは Kinematic に設定します。
Launchで確認します。
ぶつかるとコンソールにログを確認することができます。
しかし、TriggerObjectであるBox自体もクリックできてしまい、上画像のように浮いてしまいます。
これを避けるために、クリックしたオブジェクトがPlaneのみになるように Tag を設定します。
PlaneにTags「field」を追加します。
スクリプト「playerMove.js」を書き換えます。
「スクリプト属性」を追加。
PlayerMove.attributes.add("targetTag", {type:"string", default:"field"});
スクリプト属性からクリック時の参照するTagsを設定ができます。今回はデフォルトで「field」を設定しています。
「doRaycast()」の処理を一部書き加え。
// const result = this.app.systems.rigidbody.raycastFirst(from, to);
const result = this.app.systems.rigidbody.raycastAll(from, to).find(result => result.entity.tags.has(this.targetTag));
raycastFirst() はカメラから見てクリックした直線上にある最初の Entity だけしか参照しません。
そのため、Entity をクリックしても後ろの Plane は参照してくれません。
それを raycastAll() なら直線上の Entity を全て参照してくれます。
その中から、fieldのTagsを持っているか参照するために「find()」を使い result を返しています。
変更ができたらLaunchで確認。
オブジェクトをクリックしてもTagsにfiledを持つPlaneだけを参照しているので、浮くことがなくなります。
「playerMove.js」 変更したコードを含めたものが以下になります。
let PlayerMove = pc.createScript('playerMove');
PlayerMove.attributes.add("targetCamera", {type:"entity"});
PlayerMove.attributes.add("targetTag", {type:"string", default:"field"}); // 追加
PlayerMove.prototype.initialize = function() {
this.targetPosition = new pc.Vec3();
this.app.mouse.on(pc.EVENT_MOUSEUP, this.mouseUp, this);
this.app.on("move:able", () => {
this.app.mouse.on(pc.EVENT_MOUSEUP, this.mouseUp, this);
}, this);
this.app.on("move:unable", () => {
this.app.mouse.off(pc.EVENT_MOUSEUP, this.mouseUp, this);
}, this);
};
PlayerMove.prototype.update = function(dt) {};
PlayerMove.prototype.mouseDown = function (e) {
this.doRaycast(e.x, e.y);
this.entity.tween(this.entity.getLocalPosition()).to(this.targetPosition, 0.5, pc.Linear).start();
};
PlayerMove.prototype.doRaycast = function(screenX, screenY) {
let from = new pc.Vec3();
let to = new pc.Vec3();
if(this.targetCamera.camera.projection !== pc.PROJECTION_ORTHOGRAPHIC) {
from = this.targetCamera.getPosition();
to = this.targetCamera.camera.screenToWorld(screenX, screenY, this.targetCamera.camera.farClip);
} else {
var farClip = this.targetCamera.camera.farClip;
var nearClip = this.targetCamera.camera.nearClip;
this.targetCamera.camera.screenToWorld(screenX, screenY, nearClip, from);
this.targetCamera.camera.screenToWorld(screenX, screenY, farClip, to);
}
const result = this.app.systems.rigidbody.raycastAll(from, to).find(result => result.entity.tags.has(this.targetTag)); // 書き換え
if (!result) return;
this.targetPosition = result.point;
};
ここまでで、オブジェクトに触れたら処理するスクリプトを作成ができました。
次は処理した際に、オブジェクトの上にボタンを表示してみましょう。
チュートリアル - 箱庭・ミニスケープなコンテンツを作ってみる 3/5
コメント
0件のコメント
サインインしてコメントを残してください。