I am developing a game where I want my textured image to remain on the top of video player but currently video player always stays on the top of all views?
I am using the CocosCreator framework and typescript.
VideoPlayer, EditBox and WebView Component are appended in cc.game.container so these component will add as last child and These will appear on the top.
By following these steps you can change the order or appearance.
If you wan to put something like a video player Behind the canvas and want to
put other component above it, So first you will have to make your canvas transparent. You can do this by setting the flag of engine file "/engine/cocos2d/core/platform/CCMacro.js"
Change the flag ENABLE_TRANSPARENT_CANVAS to true
You need the change the ZOrder of canvas and video component class in the start of the script responsible for video player.
start: function () {
cc.director.setClearColor(new cc.Color(0, 0, 0, 0))
let videoElement = document.getElementsByClassName('cocosVideo')[0];
videoElement.style.zIndex = 2;
let gameCanvas = document.getElementsByClassName('gameCanvas')[0];
gameCanvas.style.position = 'relative';
gCanvas.style.zIndex = 4;
},
3.Here is the complete script to play a video over canvas.
cc.Class({
extends: cc.Component,
properties: {
video:{
default: null,
type: cc.VideoPlayer
}
},
// use this for initialization
onLoad: function () {
this.videoPlayer = this.node.getComponent(cc.VideoPlayer);
this.videoPlayer.node.on('ready-to-play', this.callback, this);
},
start: function () {
cc.director.setClearColor(new cc.Color(0, 0, 0, 0))
let videoElement = document.getElementsByClassName('cocosVideo')[0];
videoElement.style.zIndex = 2;
let gameCanvas = document.getElementsByClassName('gameCanvas')[0];
gameCanvas.style.position = 'relative';
gCanvas.style.zIndex = 4;
},
callback () {
console.log("video ready to play")
this.videoPlayer.play();
},
// called every frame
update: function (dt) {
},
});
Related
I am new in Phaser.
I want to make a background which represent the ground moving and there should be a bunch of rocks above it which I made them as a sprite group.
I made the ground as a tileSprite, and on each update I changed the tilePositionX. my problem is how to set the velocity of the rocks to match the update in the background so they appear to be on the ground and moving at the same speed of the ground.
theoretically you could measure the passed time, from the last update function call, and calculate the difference, or just eye-ball the needed velocity. (aka. try different velocities until it matches up with the background-movement):
Update:
If no physics object is needed you could move the "rock" "manually", this is very easy.
Here a quick demo, that I eye-balled:
The red mushroom, uses physics and velocity. Warning: the speed of the object can/will vary depending on the browser and hardware.
Update: The green mushroom, is moved manually via the position.
// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";
var config = {
type: Phaser.AUTO,
width: 536,
height: 150,
physics:{
default: 'arcade',
arcade: { debug: true }
},
scene: {
preload,
create,
update
}
};
var tilesprite;
var redRock;
var greenRock;
function preload ()
{
this.load.image('mushroom', 'https://labs.phaser.io/assets/sprites/mushroom16x16.png');
}
function create ()
{
tilesprite = this.add.tileSprite(400, 300, 800, 600, 'mushroom');
redRock = this.add.image(400, 40, 'mushroom').setScale(2);
redRock.setTint(0xff0000);
this.physics.add.existing(redRock);
redRock.body.setVelocityX(-60)
greenRock = this.add.image(400, 90, 'mushroom').setScale(2);
greenRock.setTint(0x00ff00);
}
function update (time, delta){
tilesprite.tilePositionX += 1;
let speedCorrection = (1000/60)/delta;
redRock.body.setVelocityX(-60 * speedCorrection )
greenRock.x -= 1;
// extra "reset" Rock
if( redRock.x + 16 < 0 ){
redRock.x = this.sys.game.canvas.width + 16;
greenRock.x = this.sys.game.canvas.width + 16;
}
}
var game = new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js">
</script>
Disclaimer: It is not the most elegant solution, but it took me literally 30 Seconds to find a matching velocity.
Minor Update:
I improved the eye-ball-method with a speed correction, it can cause minor flickering/slipping(max 1-2 pixel skips), but should move constant on "all" device.
The change is just adding a small calculation let speedCorrection = (1000/60)/delta;
Basically the problem is that after you rotate the camera, the points that are given as arguments in the callback for dragging are not what I expected. I'm guessing I have to Rotate the given points also but I just couldn't.
Can Someone explain what is going on, is this some kind of bug or what should I do in order the sprite to follow the mouse cursor?
Easiest way to explain the problem is to reproduce it:
1) Go to Phaser Example Runner
2) Copy- Paste this code:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
function create ()
{
var image = this.add.sprite(200, 300, 'eye').setInteractive();
this.cameras.main.setRotation(Math.PI);
image.on('pointerover', function () {
this.setTint(0x00ff00);
});
image.on('pointerout', function () {
this.clearTint();
});
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject) {
gameObject.setTint(0xff0000);
});
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
console.log(`x: ${dragX}, y: ${dragY}`);
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function (pointer, gameObject) {
gameObject.clearTint();
});
}
3) Open the console, drag around the Eye and look at what coordinates are given.
4) If you remove line 24 (the rotation of the camera) Everything works as expected.
(The example is taken from Phaser 3 Official examples and a bit changed for the bug)
According to Phaser's API Documentation on the setRotation() method, the rotation given in radians applies to everything rendered by the camera. Unfortunately, your pointer isn't rendered by the camera so it doesn't get the same rotated coordinates. Not sure if this is a bug with the library or just a poorly documented exception, but I believe there is a workaround.
Create 2 variables to hold an initial position and a final position:
var image = this.add.sprite(200, 300, 'eye').setInteractive();
var initial = [];
var final = [];
Populate the initial position in your .on('dragstart') method:
this.input.on('dragstart', function (pointer, gameObject) {
initial = [
gameObject.x,
gameObject.y,
pointer.x,
pointer.y
];
gameObject.setTint(0xff0000);
});
Then, populate the final variable in your .on('drag') method:
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
final = [
gameObject.x, // not necessary but keeping for variable shape consistency
gameObject.y, // not necessary but keeping for variable shape consistency
pointer.x,
pointer.y
];
gameObject.x = initial[0] + (initial[2] - final[2]);
gameObject.y = initial[1] + (initial[3] - final[3]);
});
All we're doing here is keeping track of the change in pointer position and mimicking that change in our gameObject.
I want to create a card, once clicked on, it rotates 180°.
So I want to create a card component, that has a plane for the back side and a plane for the front side.
Once clicked on the card-entity, it rotates both planes, so that is looks like the card is turning around.
So here's what I got so far:
custom component: Card, gets added X-times.
A cursor detects a mouseEnter, then I want to card to rotate.
On mouseLeave, the card rotates back to the original state.
So, how can I achieve this the best?
Multiple meshes in a custom component or something?
AFRAME.registerComponent('card', {
schema: {
material: {type:'selector'},
hoverMaterial: {type: 'selector'},
card: {type: 'selector'}
},
multiple: true,
element: null,
init: function () {
console.log("Card loaded");
var data = this.data;
this.el.setAttribute('material', 'src', data.material);
this.el.addEventListener('mouseenter', this.onMouseEnter.bind(this));
this.el.addEventListener('mouseleave', this.onMouseLeave.bind(this));
},
onMouseEnter: function() {
this.el.removeEventListener('mouseenter', this.onMouseEnter.bind(this));
this.el.setAttribute('material', 'src', this.data.hoverMaterial);
this.el.setAttribute('rotation', '0 180 0');
},
onMouseLeave: function () {
//this.el.addEventListener('mouseenter', this.onMouseEnter.bind(this));
this.el.setAttribute('material', 'src', this.data.material);
this.el.setAttribute('rotation', '0 0 0');
},
update: function (oldData) {
},
remove: function () {
this.el.removeObject3D('mesh');
}
});
Create a custom component that appends two child entities to itself with the appropriate orientations and materials - for front and back sides.
You could also add a transparent plane mesh to the component, to enable raycasting.
Reference to the HTML node is this.el and you can manipulate it like a regular HTML node.
Code sample:
AFRAME.registerComponent('card', {
// ...
addChildren: function () {
this.frontFace = document.createElement('a-entity');
this.backFace = document.createElement('a-entity');
// ...
this.el.appendChild(this.frontFace);
this.el.appendChild(this.backFace);
}
// ...
For the input use either a cursor component or the raycaster component itself. Note that you have to have a mesh on the component you are trying to use in raycasting.
I am trying to work out a way to add a text to the top left corner of the viewport when two of my sprites overlap. One of them is an item and the other is my character. I can already detect for overlap and even "pick" the item (kill the sprite) when I click a key. However I would like that a text saying something like "Click "E" to pick the sword!" appeared while the collision function is active and when I kill the sprite by picking it up the text would vanish.
I tried including the text in the collision function itself but I suppose this way I am rendering the text multiple times (the fps drops a lot) and I just want to create it once and remove it according to my purposes. My code:
function collisionHandler(dude,the_sword) {
pickObject.onDown.add(function () {
the_sword.kill();
}, this);
}
game.physics.isoArcade.overlap(dude, the_sword, collisionHandler, null, this);
// message saying to pick // Where to put this?
var style = { font: "30px Arial", fill: "#ff0044"};
var pick_message = this.game.add.text(0,20,"Click 'E' to pick up the sword!",style);
pick_message.fixedToCamera = true;
Any idea on how to do this?
In your 'create' function:
var style = { font: "30px Arial", fill: "#ff0044"};
var pick_message = this.game.add.text(0,20,"Click 'E' to pick up the sword!",style);
pick_message.fixedToCamera = true;
pick_message.visible = false;
Then:
function collisionHandler(dude,the_sword) {
pick_message.visible = true;
pickObject.onDown.add(function () {
the_sword.kill();
pick_message.visible = false;
}, this);
}
game.physics.isoArcade.overlap(dude, the_sword, collisionHandler, null, this);
Something like that should work. If you want to perform other action, like opening the door, you can use:
pick_message.setText("Click 'Q' to open the door!");
You don't have to create new text evertime, you can use one for different purposes.
How can background image be set in repeat effect in cocos creater ?
If character runs, back image should be flow backwards, but I want to background repeatedly continuously repeated by using one device size image file.
I think you can do this by using two background images, placed one after the other, with anchors 0,0, size assumed to be same as canvas size (Images not placed inside the canvas). This script applied to both images can achieve that effect, in simplest form.
cc.Class({
extends: cc.Component,
properties: {
// speed of scrolling
speed: 0,
// reset to position
bgwidth: 0
},
// use this for initialization
onLoad: function () {
},
// called every frame, uncomment this function to activate update callback
update: function (dt) {
var x = this.node.x;
x -= this.speed * dt;
if (x <= -this.bgwidth) {
x += this.bgwidth*2;
}
this.node.x = x;
},
});