How can set pointerDown for each of rectangle on Phaser 3 - javascript

I’m trying to set up the Conway's Game of Life using Phaser.
My question is this: how can I make a Rectangular of the Phaser.geom class contain a click event?
Class Dots:
import 'phaser';
const COLOUR_ALIVE = 0xffffff;
const COLOUR_DEAD = 0x00000;
export class Dots extends Phaser.Geom.Rectangle {
public alive: number;
public fillColor: number;
public id: string;
constructor(scene, x, y, width, height, alive, id?) {
super(x, y, width, height);
this.alive = alive;
if(this.alive == 1){
this.fillColor = COLOUR_ALIVE;
} else {
this.fillColor = COLOUR_DEAD;
}
this.id = id;
console.log(id);
}
public isAlive():boolean{
return (this.alive == 1);
}
public returnAliveValue():number{
return this.alive;
}
public getFillColor(): number{
return this.fillColor;
}
public dead(){
this.alive = 0;
this.fillColor = COLOUR_DEAD;
}
public setAlive(){
this.alive = 1;
this.fillColor = COLOUR_ALIVE;
}
public click(pointer, gameobject){
console.log(pointer, gameobject);
}
}
Class Game:
import 'phaser';
import {Dots} from './classes/Dots'
const square_size = 10;
const pixel_height = 600;
const pixel_width = 800;
const DOTS = 100;
export default class Demo extends Phaser.Scene
{
private alives: Dots[] = [];
private graphics:Phaser.GameObjects.Graphics = null;
public timeElapsed: number;
public maxTime: number;
public cont = 0;
constructor ()
{
super('demo');
this.timeElapsed = 0;
this.maxTime = 1;
}
preload ()
{
}
draw () {
this.graphics = this.add.graphics();
//Afegim les fitxes vives
let pointer = this.input.activePointer;
this.alives.forEach((rectangle:Dots) => {
this.graphics.fillStyle(rectangle.getFillColor(), 1);
this.graphics.fillRectShape(rectangle);
this.graphics.setInteractive({
hitArea: new Phaser.Geom.Rectangle(0, 22, 27, 29),
hitAreaCallback: Phaser.Geom.Rectangle.Contains,
useHandCursor: true
}, (evt, geom) => {
if(pointer.isDown){
console.log(evt, geom);
}
});
});
}
destroy(obj:Phaser.GameObjects.Graphics) {
obj.destroy();
}
intersects(object1:Dots, object2:Dots){
let x = object1.x;
let y = object1.y;
let intersects = false;
if(object2.x == x - square_size && y == object2.y){
//Bloque izquierda
intersects = true;
} else if( object2.x == x + square_size && y == object2.y){
//Bloque derecha
intersects = true;
}
if(object2.y == y - square_size && x == object2.x){
//Bloque superior
intersects = true;
} else if(object2.y == y + square_size && x == object2.x){
//Bloque inferior
intersects = true;
}
if(object2.x == x - square_size && object2.y == y - square_size){
// Bloque izquierda superior
intersects = true;
} else if (object2.x == x - square_size && object2.y == y + square_size){
// Bloque izquierda inferior
intersects = true;
}
if(object2.x == x + square_size && object2.y == y - square_size){
// Bloque derecha superior
intersects = true;
} else if (object2.x == x + square_size && object2.y == y + square_size){
// Bloque derecha inferior
intersects = true;
}
return intersects;
}
searchArrIntersect(){
this.alives.forEach((x) => {
if(x.alive == 1){
let intersections = 0;
this.alives.forEach((y) => {
if(x != y){
let intersects = this.intersects(x, y);
if(intersects){
intersections ++;
}
}
});
if(intersections == 2 || intersections == 3){
x.isAlive();
}
if(intersections >= 3){
x.dead();
}
} else{
//fichas muertas
let intersections = 0;
this.alives.forEach((y) => {
if(x != y){
let intersects = this.intersects(x, y);
if(intersects){
intersections ++;
}
}
});
if(intersections == 3){
x.isAlive();
}
}
});
}
castObjectIntersects(object_search:Dots):Dots{
let dot_intersect = null;
this.alives.forEach((x, index) => {
if(x.x == object_search.x && x.y == object_search.y){
dot_intersect = x;
}
});
return dot_intersect;
}
create ()
{
let positions = [
//cross
// {x: pixel_width/2 - square_size, y: pixel_height/2, alive:1, id:'left'},
// {x: pixel_width/2 + square_size, y: pixel_height/2, alive:1, id:'right'},
// {x: pixel_width/2, y: pixel_height/2, alive:1, id:'center'},
// {x: pixel_width/2, y: pixel_height/2 - square_size, alive:1, id:'up'},
// {x: pixel_width/2, y: pixel_height/2 + square_size, alive:1, id:'down'},
// //borders
// //left
// {x: pixel_width/2 - square_size, y: pixel_height/2 - square_size, alive: 1, id:'left_up'},
// {x: pixel_width/2 - square_size, y: pixel_height/2 + square_size, alive: 1, id:'left_down'},
// //right
// {x: pixel_width/2 + square_size, y: pixel_height/2 - square_size, alive:0, id:'right_up'},
// {x: pixel_width/2 + square_size, y: pixel_height/2 + square_size, alive:0, id:'right_down'},
];
for(let i = 0; i < pixel_width; i+=10){
for(let j = 0; j < pixel_height; j+=10){
positions.push({x: i, y: j, alive:0, id:`${i}-${j}`});
}
}
positions.forEach((obj) => {
this.alives.push(new Dots(this, obj.x, obj.y, square_size, square_size, obj.alive, obj.id));
});
for(let i = 0; i <= DOTS; i++){
let random_length = Math.floor(Math.random() * (this.alives.length - 1 + 1) + 1);
let dot = this.alives[random_length];
dot.setAlive();
}
this.draw();
}
update(time: number, delta: number): void {
let deltaInSecond = delta/1000; // convert it to second
this.timeElapsed = this.timeElapsed + deltaInSecond;
if(this.timeElapsed >= this.maxTime) // if the time elapsed already more than 1 second
{
this.searchArrIntersect();
this.destroy(this.graphics);
this.draw();
// this.maxTime = 1200;
this.timeElapsed = 0;
}
}
}
const config = {
type: Phaser.AUTO,
backgroundColor: '#000000',
width: pixel_width,
height: pixel_height,
render: {
pixelArt: true
},
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
},
scene: Demo
};
const game = new Phaser.Game(config);

You are setting interactive on the graphics serveral time, it the forEach-loop. I think this can be done only once, so you are overriding it, but I'm no expert.
I would set the interactivity once, for the whole region:
this.graphics.setInteractive({ useHandCursor: true,
hitArea: new Phaser.Geom.Rectangle(0, 0, pixel_width, pixel_height),
hitAreaCallback: Phaser.Geom.Rectangle.Contains,
})
And than in the "click event" select the Rectangle/Dot
this.graphics.on( 'pointerdown', function(){
// ...
});
To get the Rectangle/Dot clicked, there are many ways, here is one:
this.graphics.on( 'pointerdown', function(pointer){
let selected = this.alives.find( point => Phaser.Geom.Rectangle.Contains( new
Phaser.Geom.Rectangle(point.x, point.y, point.width, point.height), pointer.worldX, pointer.worldY
));
console.log('pointerover', pointer, selected);
}, this);
btw.:
I would add the graphics once in the create method:
create () {
// ...
this.graphics = this.add.graphics();
this.graphics.setInteractive({
// ...
});
this.graphics.on('pointerdown', () => {
// ...
});
this.draw();
}
and in the draw method just clear the graphics-object.
draw () {
this.graphics.clear();
// ...
}

Related

Custom webgl engine with Cannon.js , How to resolve jumping, blocking and walk

I look at stackoverflow other people similar problems a they have very similar solution but all examples are done in three.js (Not in my case).
Jump is relative good working at the moment, i powered gravity (double it).
Stairs also works fine even without jumping it is ok for me.
I put one big cube to make blocking volume but i dont now how to make player to simple stops because i use WASD for body set position. My player in big cube just have big jump , i wanna prevent WASD body set position in moment of first touch.
Some solutions [not yet tested]:
1] To make movement only with force [not set position] => [possible not nature movements]
2] Make collide detection then prevent set position => [possible angle problems]
3] Some other solution....
All related code is visible in example.
Matrix-engine example for FPS:
import App from '../program/manifest';
import * as CANNON from 'cannon';
import {ENUMERATORS, ORBIT_FROM_ARRAY, OSCILLATOR, randomFloatFromTo} from '../lib/utility';
export var runThis = (world) => {
// Camera
canvas.style.cursor = 'none';
App.camera.FirstPersonController = true;
matrixEngine.Events.camera.fly = false;
App.camera.speedAmp = 0.01;
matrixEngine.Events.camera.yPos = 2;
// Audio effects
App.sounds.createAudio('shoot', 'res/music/single-gunshot.mp3', 5);
// Prevent right click context menu
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
});
// Override mouse up
App.events.CALCULATE_TOUCH_UP_OR_MOUSE_UP = () => {
App.scene.FPSTarget.glBlend.blendParamSrc = matrixEngine.utility.ENUMERATORS.glBlend.param[4];
App.scene.FPSTarget.glBlend.blendParamDest = matrixEngine.utility.ENUMERATORS.glBlend.param[4];
App.scene.FPSTarget.geometry.setScale(0.1);
App.scene.xrayTarget.visible = false;
};
// Override right mouse down
matrixEngine.Events.SYS.MOUSE.ON_RIGHT_BTN_PRESSED = (e) => {
App.scene.FPSTarget.geometry.setScale(0.6);
App.scene.FPSTarget.glBlend.blendParamSrc = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.FPSTarget.glBlend.blendParamDest = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.xrayTarget.visible = true;
};
// Override mouse down
App.events.CALCULATE_TOUCH_DOWN_OR_MOUSE_DOWN = (ev, mouse) => {
// `checkingProcedure` gets secound optimal argument
// for custom ray origin target.
if(mouse.BUTTON_PRESSED == 'RIGHT') {
// Zoom
} else {
// This call represent `SHOOT` Action.
// And it is center of screen
matrixEngine.raycaster.checkingProcedure(ev, {
clientX: ev.target.width / 2,
clientY: ev.target.height / 2
});
App.sounds.play('shoot');
}
};
window.addEventListener('ray.hit.event', (ev) => {
console.log("You shoot the object! Nice!", ev);
// Physics force apply also change ambienty light.
if(ev.detail.hitObject.physics.enabled == true) {
// Shoot the object - apply force
ev.detail.hitObject.physics.currentBody.force.set(0, 0, 1000);
// Apply random diff color
if(ev.detail.hitObject.LightsData) ev.detail.hitObject.LightsData.ambientLight.set(
randomFloatFromTo(0, 2), randomFloatFromTo(0, 2), randomFloatFromTo(0, 2));
}
});
// Load obj seq animation
const createObjSequence = (objName) => {
function onLoadObj(meshes) {
for(let key in meshes) {
matrixEngine.objLoader.initMeshBuffers(world.GL.gl, meshes[key]);
}
var textuteImageSamplers2 = {
source: [
"res/bvh-skeletal-base/swat-guy/textures/Ch15_1001_Diffuse.png" // ,
// "res/bvh-skeletal-base/swat-guy/textures/Ch15_1001_Diffuse.png"
],
mix_operation: "multiply", // ENUM : multiply , divide
};
var animArg = {
id: objName,
meshList: meshes,
currentAni: 0,
animations: {
active: 'walk',
walk: {
from: 0,
to: 20,
speed: 3
}
}
};
world.Add("obj", 1, objName, textuteImageSamplers2, meshes[objName], animArg);
// Fix object orientation - this can be fixed also in blender.
matrixEngine.Events.camera.yaw = 0;
// Add collision cube to the local player.
world.Add("cube", 0.5, "playerCollisonBox");
var collisionBox = new CANNON.Body({
mass: 500,
linearDamping: 0.001,
position: new CANNON.Vec3(0, 0, 0),
shape: new CANNON.Box(new CANNON.Vec3(3, 3, 3))// new CANNON.Sphere(2)
});
physics.world.addBody(collisionBox);
App.scene.playerCollisonBox.physics.currentBody = collisionBox;
App.scene.playerCollisonBox.physics.enabled = true;
App.scene.playerCollisonBox.physics.currentBody.fixedRotation = true;
App.scene.playerCollisonBox.geometry.setScale(0.02);
App.scene.playerCollisonBox.glBlend.blendEnabled = true;
App.scene.playerCollisonBox.glBlend.blendParamSrc = ENUMERATORS.glBlend.param[5];
App.scene.playerCollisonBox.glBlend.blendParamDest = ENUMERATORS.glBlend.param[6];
// test
addEventListener('hit.keyDown', (e) => {
// console.log('Bring to the top level', e.detail.keyCode);
// dont mess in events
if(e.detail.keyCode == 32) {
setTimeout(() => {
App.scene.playerCollisonBox.physics.currentBody.force.set(0, 0, 111)
}, 250)
} else if(e.detail.keyCode == 87) {
// Good place for blocking volume
// App.scene.playerCollisonBox.physics.currentBody.force.set(0,10,0)
setTimeout(() => {
// App.scene.playerCollisonBox.physics.currentBody.force.set(0,100,0)
}, 100);
}
});
var playerUpdater = {
UPDATE: () => {
App.scene[objName].rotation.rotateY(
matrixEngine.Events.camera.yaw + 180)
var detPitch;
var limit = 2;
if(matrixEngine.Events.camera.pitch < limit &&
matrixEngine.Events.camera.pitch > -limit) {
detPitch = matrixEngine.Events.camera.pitch * 2;
} else if(matrixEngine.Events.camera.pitch > limit) {
detPitch = limit * 2;
} else if(matrixEngine.Events.camera.pitch < -(limit + 2)) {
detPitch = -(limit + 2) * 2;
}
if(matrixEngine.Events.camera.virtualJumpActive == true) {
// invert logic
// Scene object set
App.scene[objName].rotation.rotateX(-detPitch);
var detPitchPos = matrixEngine.Events.camera.pitch;
if(detPitchPos > 4) detPitchPos = 4;
App.scene.playerCollisonBox.physics.currentBody.mass = 10;
App.scene.playerCollisonBox.physics.currentBody.force.set(0, 0, 700);
App.scene[objName].position.setPosition(
App.scene.playerCollisonBox.physics.currentBody.position.x,
App.scene.playerCollisonBox.physics.currentBody.position.z,
App.scene.playerCollisonBox.physics.currentBody.position.y
)
// Cannonjs object set / Switched Z - Y
matrixEngine.Events.camera.xPos = App.scene.playerCollisonBox.physics.currentBody.position.x;
matrixEngine.Events.camera.zPos = App.scene.playerCollisonBox.physics.currentBody.position.y;
matrixEngine.Events.camera.yPos = App.scene.playerCollisonBox.physics.currentBody.position.z;
App.scene.playerCollisonBox.
physics.currentBody.angularVelocity.set(0, 0, 0);
setTimeout(() => {
matrixEngine.Events.camera.virtualJumpActive = false;
App.scene.playerCollisonBox.physics.currentBody.mass = 550;
}, 1350);
} else {
// Make more stable situation
App.scene.playerCollisonBox.physics.currentBody.mass = 500;
App.scene.playerCollisonBox.physics.currentBody.quaternion.setFromEuler(0,0,0)
// Tamo tu iznad duge nebo zri...
// Cannonjs object set
// Switched Z - Y
matrixEngine.Events.camera.yPos = App.scene.playerCollisonBox.physics.currentBody.position.z;
// Scene object set
App.scene[objName].rotation.rotateX(-detPitch);
var detPitchPos = matrixEngine.Events.camera.pitch;
if(detPitchPos > 4) detPitchPos = 4;
App.scene[objName].position.setPosition(
matrixEngine.Events.camera.xPos,
matrixEngine.Events.camera.yPos, // - 0.3 + detPitchPos / 50,
// App.scene.playerCollisonBox.physics.currentBody.position.y,
matrixEngine.Events.camera.zPos,
)
// Cannonjs object set
// Switched Z - Y
App.scene.playerCollisonBox.
physics.currentBody.position.set(
matrixEngine.Events.camera.xPos,
matrixEngine.Events.camera.zPos,
matrixEngine.Events.camera.yPos)
// App.scene.playerCollisonBox.physics.currentBody.position.y)
}
}
};
App.updateBeforeDraw.push(playerUpdater);
// Player Energy status
App.scene.player.energy = {};
for(let key in App.scene.player.meshList) {
App.scene.player.meshList[key].setScale(1.85);
}
// Target scene object
var texTarget = {
source: [
"res/bvh-skeletal-base/swat-guy/target.png",
"res/bvh-skeletal-base/swat-guy/target.png"
],
mix_operation: "multiply",
};
world.Add("squareTex", 0.25, 'FPSTarget', texTarget);
App.scene.FPSTarget.position.setPosition(0, 0, -4);
App.scene.FPSTarget.glBlend.blendEnabled = true;
App.scene.FPSTarget.glBlend.blendParamSrc = matrixEngine.utility.ENUMERATORS.glBlend.param[4];
App.scene.FPSTarget.glBlend.blendParamDest = matrixEngine.utility.ENUMERATORS.glBlend.param[4];
App.scene.FPSTarget.isHUD = true;
App.scene.FPSTarget.geometry.setScale(0.1);
// Energy active bar
// Custom generic textures. Micro Drawing.
// Example for arg shema square for now only.
var options = {
squareShema: [8, 8],
pixels: new Uint8Array(8 * 8 * 4)
};
// options.pixels.fill(0);
App.scene.player.energy.value = 8;
App.scene.player.updateEnergy = function(v) {
this.energy.value = v;
var t = App.scene.energyBar.preparePixelsTex(App.scene.energyBar.specialValue);
App.scene.energyBar.textures.pop()
App.scene.energyBar.textures.push(App.scene.energyBar.createPixelsTex(t));
};
function preparePixelsTex(options) {
var I = 0, R = 0, G = 0, B = 0, localCounter = 0;
for(var funny = 0;funny < 8 * 8 * 4;funny += 4) {
if(localCounter > 7) {
localCounter = 0;
}
if(localCounter < App.scene.player.energy.value) {
I = 128;
if(App.scene.player.energy.value < 3) {
R = 255;
G = 0;
B = 0;
I = 0;
} else if(App.scene.player.energy.value > 2 && App.scene.player.energy.value < 5) {
R = 255;
G = 255;
B = 0;
} else {
R = 0;
G = 255;
B = 0;
}
} else {
I = 0;
R = 0;
G = 0;
B = 0;
}
options.pixels[funny] = R;
options.pixels[funny + 1] = G;
options.pixels[funny + 2] = B;
options.pixels[funny + 3] = 0;
localCounter++;
}
return options;
}
var tex2 = {
source: [
"res/images/hud/energy-bar.png",
"res/images/hud/energy-bar.png"
],
mix_operation: "multiply",
};
world.Add("squareTex", 1, 'energyBar', tex2);
App.scene.energyBar.glBlend.blendEnabled = true;
App.scene.energyBar.glBlend.blendParamSrc = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.energyBar.glBlend.blendParamDest = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.energyBar.isHUD = true;
// App.scene.energy.visible = false;
App.scene.energyBar.position.setPosition(0, 1.1, -3);
App.scene.energyBar.geometry.setScaleByX(1)
App.scene.energyBar.geometry.setScaleByY(0.05)
App.scene.energyBar.preparePixelsTex = preparePixelsTex;
options = preparePixelsTex(options);
// App.scene.energyBar.textures[0] = App.scene.energyBar.createPixelsTex(options);
App.scene.energyBar.textures.push(App.scene.energyBar.createPixelsTex(options));
App.scene.energyBar.specialValue = options;
}
matrixEngine.objLoader.downloadMeshes(
matrixEngine.objLoader.makeObjSeqArg(
{
id: objName,
// path: "res/bvh-skeletal-base/swat-guy/anims/swat-multi",
path: "res/bvh-skeletal-base/swat-guy/FPShooter-hands/FPShooter-hands",
from: 1,
to: 20
}),
onLoadObj
);
};
let promiseAllGenerated = [];
const objGenerator = (n) => {
for(var j = 0;j < n;j++) {
promiseAllGenerated.push(new Promise((resolve) => {
setTimeout(() => {
world.Add("cubeLightTex", 1, "CUBE" + j, tex);
var b2 = new CANNON.Body({
mass: 1,
linearDamping: 0.01,
position: new CANNON.Vec3(1, -14.5, 15),
shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1))
});
physics.world.addBody(b2);
App.scene['CUBE' + j].physics.currentBody = b2;
App.scene['CUBE' + j].physics.enabled = true;
resolve();
}, 1000 * j);
}));
}
}
// objGenerator(15);
createObjSequence('player');
Promise.all(promiseAllGenerated).then((what) => {
console.info(`Runtime wait for some generetion of scene objects,
then swap scene array index for target ->
must be manual setup for now!`, what);
// swap(5, 19, matrixEngine.matrixWorld.world.contentList);
});
// Add ground for physics bodies.
var tex = {
source: ["res/images/complex_texture_1/diffuse.png"],
mix_operation: "multiply",
};
// Load Physics world.
// let gravityVector = [0, 0, -9.82];
let gravityVector = [0, 0, -29.82];
let physics = world.loadPhysics(gravityVector);
// Add ground
var groundBody = new CANNON.Body({
mass: 0, // mass == 0 makes the body static
position: new CANNON.Vec3(0, -15, -2)
});
var groundShape = new CANNON.Plane();
groundBody.addShape(groundShape);
physics.world.addBody(groundBody);
// Matrix engine visual
world.Add("squareTex", 1, "FLOOR_STATIC", tex);
App.scene.FLOOR_STATIC.geometry.setScaleByX(20);
App.scene.FLOOR_STATIC.geometry.setScaleByY(20);
App.scene.FLOOR_STATIC.position.SetY(-2);
App.scene.FLOOR_STATIC.position.SetZ(-15);
App.scene.FLOOR_STATIC.rotation.rotx = 90;
// Target x-ray
// See through the objects.
// In webGL context it is object how was drawn before others.
var texTarget = {
source: [
"res/bvh-skeletal-base/swat-guy/target-night.png"
],
mix_operation: "multiply",
};
world.Add("squareTex", 0.18, 'xrayTarget', texTarget);
App.scene.xrayTarget.glBlend.blendEnabled = true;
App.scene.xrayTarget.glBlend.blendParamSrc = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.xrayTarget.glBlend.blendParamDest = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.xrayTarget.isHUD = true;
App.scene.xrayTarget.visible = false;
App.scene.xrayTarget.position.setPosition(-0.3, 0.27, -4);
// Energy
var tex1 = {
source: [
"res/images/hud/energy.png"
],
mix_operation: "multiply",
};
world.Add("squareTex", 0.5, 'energy', tex1);
App.scene.energy.glBlend.blendEnabled = true;
App.scene.energy.glBlend.blendParamSrc = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.energy.glBlend.blendParamDest = matrixEngine.utility.ENUMERATORS.glBlend.param[5];
App.scene.energy.isHUD = true;
// App.scene.energy.visible = false;
App.scene.energy.position.setPosition(-1, 1.15, -3);
App.scene.energy.geometry.setScaleByX(0.35)
App.scene.energy.geometry.setScaleByY(0.1)
// good for fix rotation in future
world.Add("cubeLightTex", 1, "FLOOR2", tex);
var b2 = new CANNON.Body({
mass: 0,
linearDamping: 0.01,
position: new CANNON.Vec3(1, -14.5, -1),
shape: new CANNON.Box(new CANNON.Vec3(3, 1, 1))
});
physics.world.addBody(b2);
App.scene['FLOOR2'].position.setPosition(1, -1, -14.5)
App.scene['FLOOR2'].geometry.setScaleByX(3);
App.scene['FLOOR2'].physics.currentBody = b2;
App.scene['FLOOR2'].physics.enabled = true;
world.Add("cubeLightTex", 2, "FLOOR3", tex);
var b3 = new CANNON.Body({
mass: 0,
linearDamping: 0.01,
position: new CANNON.Vec3(0, -19, 0),
shape: new CANNON.Box(new CANNON.Vec3(3, 3, 3))
});
physics.world.addBody(b3);
App.scene['FLOOR3'].position.setPosition(0, 0, -19)
// App.scene['FLOOR3'].geometry.setScaleByX(3);
App.scene['FLOOR3'].physics.currentBody = b3;
App.scene['FLOOR3'].physics.enabled = true;
world.Add("cubeLightTex", 5, "WALL_BLOCK", tex);
var b5 = new CANNON.Body({
mass: 0,
linearDamping: 0.01,
position: new CANNON.Vec3(10, -19, 0),
shape: new CANNON.Box(new CANNON.Vec3(5, 5, 5))
});
physics.world.addBody(b5);
App.scene['WALL_BLOCK'].position.setPosition(10, 0, -19)
// App.scene['WALL_BLOCK'].geometry.setScaleByX(3);
App.scene['WALL_BLOCK'].physics.currentBody = b5;
App.scene['WALL_BLOCK'].physics.enabled = true;
};
Any suggestion ?

Scroll not works on mobile PIXI JS

I tried to make a canva which can scroll on mobile and desktop.
I have succeeded to scroll on desktop and even with touchpad, but i can't to find a way to scroll on my mobile.
I have already manage the scroll with mouse wheel but i haven't succeeded with touchscreen.
Do you have an idea to do work this below:
this.container = new PIXI.Container();
this.app.stage.addChild(this.container);
this.images = [t1, t2, t3, t4];
this.WHOLEWIDTH = this.images.length*(this.width + this.margin)
loadImages(this.images, (images)=>{
this.loadImages = images;
this.add()
this.render()
this.scrollEvent();
})
}
scrollEvent() {
document.addEventListener(
'mousewheel',
(e) => {
this.scrollTarget = e.wheelDelta / 3;
},
{ passive: true },
);
}
add() {
let parent = {
w: this.width,
h: this.height,
};
this.thumbs = [];
this.loadImages.forEach((img, i) => {
var nameEnum = {
0: { name: 'Ecocampus3', value: '/Ecocampus3' },
1: { name: 'Hoppin World', value: '/HoppinWorld' },
2: { name: 'Distrame', value: '/Distrame' },
3: { name: 'Club les Piranhas du Nord', value: '/CAPN' },
};
let texture = PIXI.Texture.from(img.img);
texture.title = nameEnum[i];
const sprite = new PIXI.Sprite(texture);
let container = new PIXI.Container();
let spriteContainer = new PIXI.Container();
let mask = new PIXI.Sprite(PIXI.Texture.WHITE);
mask.width = this.width;
mask.height = this.height;
sprite.mask = mask;
sprite.anchor.set(0.5);
sprite.position.set(sprite.texture.orig.width / 2, sprite.texture.orig.height / 2);
let image = {
w: sprite.texture.orig.width,
h: sprite.texture.orig.height,
};
let cover = fit(image, parent);
spriteContainer.position.set(cover.left, cover.top);
spriteContainer.scale.set(cover.scale, cover.scale);
container.x = (this.margin + this.width) * i;
container.y = this.height / 10;
spriteContainer.addChild(sprite);
container.interactive = true;
container.on('mouseover', this.mouseOn, { passive: true });
container.on('mouseout', this.mouseOut, { passive: true });
container.on('click', this.redirect, { passive: true });
container.on('touchstart', this.redirect, { passive: true });
container.on('touchmove', this.redirect, { passive: true });
container.addChild(spriteContainer);
container.addChild(mask);
this.container.addChild(container);
this.thumbs.push(container);
});
}
redirect(e) {
let e1 = e.currentTarget.children[0].children[0];
let e2 = e1.texture.title.value;
window.location.replace(e2);
}
mouseOut(e) {
let e1 = e.currentTarget.children[0].children[0];
gsap.to(e1.scale, {
duration: 1,
x: 1,
y: 1,
});
e1.children[0].text = '';
}
mouseOn(e) {
let e1 = e.target.children[0].children[0];
const skewStyle = new PIXI.TextStyle({
fontFamily: 'Raleway',
fontSize: '60px',
dropShadowColor: '#fff',
fill: '#fff',
fontWeight: 'bold',
});
let e2 = e1.texture.title.name;
const basicText1 = new PIXI.Text(e2, skewStyle);
basicText1.x = -400;
basicText1.y = 100;
gsap.to(e1.scale, {
duration: 1,
x: 1.1,
y: 1.1,
});
if (e1.children[0]) {
e1.children[0].text = e2;
} else {
e1.addChild(basicText1);
}
}
calcPos(scr, pos) {
let temp = ((scr + pos + this.WHOLEWIDTH + this.width + this.margin) % this.WHOLEWIDTH) - this.width - this.margin;
return temp;
}
render() {
this.app.ticker.add(() => {
this.app.renderer.render(this.container);
this.scroll -= (this.scroll - this.scrollTarget) * 0.1;
this.scrollTarget *= 0.9;
this.thumbs.forEach((th) => {
th.position.x = this.calcPos(this.scroll, th.position.x);
});
});
}
Thank you in advance :D

How would I add a level system for the score increasing?

I am making a slight Tetris remake and I wanted to add a leveling system for when my score reaches, for example, 100, the speed that the blocks go down will also increase. How would I go about doing this? I have the entirety of the javascript code right here so please let me know what I can do to fix it:
//-------------------------------------------------------------------------
// base helper methods
//-------------------------------------------------------------------------
function get(id) { return document.getElementById(id); }
function hide(id) { get(id).style.visibility = 'hidden'; }
function show(id) { get(id).style.visibility = null; }
function html(id, html) { get(id).innerHTML = html; }
function timestamp() { return new Date().getTime(); }
function random(min, max) { return (min + (Math.random() * (max - min))); }
function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; }
if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
}
}
//-------------------------------------------------------------------------
// game constants
//-------------------------------------------------------------------------
var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 },
DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 },
stats = new Stats(),
canvas = get('canvas'),
ctx = canvas.getContext('2d'),
ucanvas = get('upcoming'),
uctx = ucanvas.getContext('2d'),
speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds)
nx = 10, // width of tetris court (in blocks)
ny = 20, // height of tetris court (in blocks)
nu = 5; // width/height of upcoming preview (in blocks)
//-------------------------------------------------------------------------
// game variables (initialized during reset)
//-------------------------------------------------------------------------
var dx, dy, // pixel size of a single tetris block
blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece'
actions, // queue of user actions (inputs)
playing, // true|false - game is in progress
dt, // time since starting this game
current, // the current piece
next, // the next piece
score, // the current score
vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine)
rows, // number of completed rows in the current game
step; // how long before current piece drops by 1 row
//-------------------------------------------------------------------------
// tetris pieces
//
// blocks: each element represents a rotation of the piece (0, 90, 180, 270)
// each element is a 16 bit integer where the 16 bits represent
// a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0
//
// 0100 = 0x4 << 3 = 0x4000
// 0100 = 0x4 << 2 = 0x0400
// 1100 = 0xC << 1 = 0x00C0
// 0000 = 0x0 << 0 = 0x0000
// ------
// 0x44C0
//
//-------------------------------------------------------------------------
var i = { size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'cyan' };
var j = { size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'blue' };
var l = { size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'orange' };
var o = { size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'yellow' };
var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'lime' };
var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'purple' };
var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'red' };
var p = { size: 3, blocks: [0x0F00, 0x2222, 0x00F0,], color: 'maroon' };
//------------------------------------------------
// do the bit manipulation and iterate through each
// occupied block (x,y) for a given piece
//------------------------------------------------
function eachblock(type, x, y, dir, fn) {
var bit, result, row = 0, col = 0, blocks = type.blocks[dir];
for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) {
if (blocks & bit) {
fn(x + col, y + row);
}
if (++col === 4) {
col = 0;
++row;
}
}
}
//-----------------------------------------------------
// check if a piece can fit into a position in the grid
//-----------------------------------------------------
function occupied(type, x, y, dir) {
var result = false
eachblock(type, x, y, dir, function(x, y) {
if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y))
result = true;
});
return result;
}
function unoccupied(type, x, y, dir) {
return !occupied(type, x, y, dir);
}
//-----------------------------------------
// start with 4 instances of each piece and
// pick randomly until the 'bag is empty'
//-----------------------------------------
var pieces = [];
function randomPiece() {
if (pieces.length == 0)
pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,p,p,p,p];
var type = pieces.splice(random(0, pieces.length-1), 1)[0];
return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 };
}
//-------------------------------------------------------------------------
// GAME LOOP
//-------------------------------------------------------------------------
function run() {
showStats(); // initialize FPS counter
addEvents(); // attach keydown and resize events
var last = now = timestamp();
function frame() {
now = timestamp();
update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab
draw();
stats.update();
last = now;
requestAnimationFrame(frame, canvas);
}
resize(); // setup all our sizing information
reset(); // reset the per-game variables
frame(); // start the first frame
}
function showStats() {
stats.domElement.id = 'stats';
get('menu').appendChild(stats.domElement);
}
function addEvents() {
document.addEventListener('keydown', keydown, false);
window.addEventListener('resize', resize, false);
}
function resize(event) {
canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size
canvas.height = canvas.clientHeight; // (ditto)
ucanvas.width = ucanvas.clientWidth;
ucanvas.height = ucanvas.clientHeight;
dx = canvas.width / nx; // pixel size of a single tetris block
dy = canvas.height / ny; // (ditto)
invalidate();
invalidateNext();
}
function keydown(ev) {
var handled = false;
if (playing) {
switch(ev.keyCode) {
case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break;
case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break;
case KEY.UP: actions.push(DIR.UP); handled = true; break;
case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break;
case KEY.ESC: lose(); handled = true; break;
}
}
else if (ev.keyCode == KEY.SPACE) {
play();
handled = true;
}
if (handled)
ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers)
}
//-------------------------------------------------------------------------
// GAME LOGIC
//-------------------------------------------------------------------------
function play() { hide('start'); reset(); playing = true; }
function lose() { show('start'); setVisualScore(); playing = false; }
function setVisualScore(n) { vscore = n || score; invalidateScore(); }
function setScore(n) { score = n; setVisualScore(n); }
function addScore(n) { score = score + n; }
function clearScore() { setScore(0); }
function clearRows() { setRows(0); }
function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); }
function addRows(n) { setRows(rows + n); }
function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); }
function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); }
function clearBlocks() { blocks = []; invalidate(); }
function clearActions() { actions = []; }
function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); }
function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); }
function reset() {
dt = 0;
clearActions();
clearBlocks();
clearRows();
clearScore();
setCurrentPiece(next);
setNextPiece();
}
function update(idt) {
if (playing) {
if (vscore < score)
setVisualScore(vscore + 1);
handle(actions.shift());
dt = dt + idt;
if (dt > step) {
dt = dt - step;
drop();
}
}
}
function handle(action) {
switch(action) {
case DIR.LEFT: move(DIR.LEFT); break;
case DIR.RIGHT: move(DIR.RIGHT); break;
case DIR.UP: rotate(); break;
case DIR.DOWN: drop(); break;
}
}
function move(dir) {
var x = current.x, y = current.y;
switch(dir) {
case DIR.RIGHT: x = x + 1; break;
case DIR.LEFT: x = x - 1; break;
case DIR.DOWN: y = y + 1; break;
}
if (unoccupied(current.type, x, y, current.dir)) {
current.x = x;
current.y = y;
invalidate();
return true;
}
else {
return false;
}
}
function rotate() {
var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1);
if (unoccupied(current.type, current.x, current.y, newdir)) {
current.dir = newdir;
invalidate();
}
}
//This is how we make the piece drop down and place:
function drop() {
if (!move(DIR.DOWN)) {
addScore(10);
dropPiece();
removeLines();
setCurrentPiece(next);
setNextPiece(randomPiece());
clearActions();
if (occupied(current.type, current.x, current.y, current.dir)) {
lose();
}
}
}
function dropPiece() {
eachblock(current.type, current.x, current.y, current.dir, function(x, y) {
setBlock(x, y, current.type);
});
}
function removeLines() {
var x, y, complete, n = 0;
for(y = ny ; y > 0 ; --y) {
complete = true;
for(x = 0 ; x < nx ; ++x) {
if (!getBlock(x, y))
complete = false;
}
if (complete) {
removeLine(y);
y = y + 1; // recheck same line
n++;
}
}
if (n > 0) {
addRows(n);
addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800
}
}
function removeLine(n) {
var x, y;
for(y = n ; y >= 0 ; --y) {
for(x = 0 ; x < nx ; ++x)
setBlock(x, y, (y == 0) ? null : getBlock(x, y-1));
}
}
//-------------------------------------------------------------------------
// RENDERING
//-------------------------------------------------------------------------
var invalid = {};
function invalidate() { invalid.court = true; }
function invalidateNext() { invalid.next = true; }
function invalidateScore() { invalid.score = true; }
function invalidateRows() { invalid.rows = true; }
function draw() {
ctx.save();
ctx.lineWidth = 1;
ctx.translate(0.5, 0.5); // for crisp 1px black lines
drawCourt();
drawNext();
drawScore();
drawRows();
ctx.restore();
}
function drawCourt() {
if (invalid.court) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (playing)
drawPiece(ctx, current.type, current.x, current.y, current.dir);
var x, y, block;
for(y = 0 ; y < ny ; y++) {
for (x = 0 ; x < nx ; x++) {
if (block = getBlock(x,y))
drawBlock(ctx, x, y, block.color);
}
}
ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary
invalid.court = false;
}
}
function drawNext() {
if (invalid.next) {
var padding = (nu - next.type.size) / 2; // half-complete attempt at centering next piece display
uctx.save();
uctx.translate(0.5, 0.5);
uctx.clearRect(0, 0, nu*dx, nu*dy);
drawPiece(uctx, next.type, padding, padding, next.dir);
uctx.strokeStyle = 'black';
uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1);
uctx.restore();
invalid.next = false;
}
}
function drawScore() {
if (invalid.score) {
html('score', ("00000" + Math.floor(vscore)).slice(-5));
invalid.score = false;
}
}
function drawRows() {
if (invalid.rows) {
html('rows', rows);
invalid.rows = false;
}
}
function drawPiece(ctx, type, x, y, dir) {
eachblock(type, x, y, dir, function(x, y) {
drawBlock(ctx, x, y, type.color);
});
}
function drawBlock(ctx, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x*dx, y*dy, dx, dy);
ctx.strokeRect(x*dx, y*dy, dx, dy)
}
//-------------------------------------------------------------------------
// FINALLY, lets run the game
//-------------------------------------------------------------------------
run();
You have a function called addScore that seems to be used to update the user's score. You could add a conditional block inside this function that will update the game speed when the new score is above the threshold you choose. Alternatively, if you would prefer to keep addScore purely focused on updating the value of the score, you could add this conditional block wherever you're calling addScore.

Letter tracing game with javascript

I want to create game like this. But I have some problem with painting SVG inside canvas. Initially I try to create levels with vanilla js (I use only vuejs), but I got a lot of bugs (I show my code below). After that I try p5js library, but I didn't found how I can fill my SVG with animation. I try to use pixijs, but it so big framework. Also I did not find a solution with createjs library. I'm tired of wasting time looking, can anyone advise me on a framework suitable for my task.
My vanilla code:
new class Game {
constructor() {
this.c = document.querySelector('canvas')
this.cx = this.c.getContext('2d')
this.init()
this.c.addEventListener('mousedown', this.onmousedown, false);
this.c.addEventListener('mouseup', this.onmouseup, false);
this.c.addEventListener('mousemove', this.onmousemove.bind(this), false);
}
init () {
this.c.height = 480;
this.c.width = 320;
this.cx.strokeStyle = 'rgb(0, 0, 50)';
this.drawletter('5');
this.pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
this.letterpixels = this.getpixelamount(255, 0, 0);
}
pixelthreshold() {
if (this.getpixelamount(0, 0, 50) / this.letterpixels > 0.35) {
console.log('you got it!');
}
}
showerror(error) {
this.mousedown = false;
console.log(error)
}
getpixelcolour(x, y) {
const index = ((y * (this.pixels.width * 4)) + (x * 4));
return {
r: this.pixels.data[index],
g: this.pixels.data[index + 1],
b: this.pixels.data[index + 2],
a: this.pixels.data[index + 3]
};
}
paint(x, y) {
const colour = this.getpixelcolour(x, y);
if (colour.a === 0) {
this.showerror('you are outside');
} else {
this.cx.beginPath();
if ((this.oldx > 0 && this.oldy > 0) &&
(Math.abs(this.oldx - x) < this.cx.lineWidth / 2 && Math.abs(this.oldy - y) < this.cx.lineWidth / 2)) {
this.cx.moveTo(this.oldx, this.oldy);
}
this.cx.lineTo(x, y);
this.cx.stroke();
this.cx.closePath();
this.oldx = x;
this.oldy = y;
}
}
onmousedown(ev) {
this.mousedown = true;
ev.preventDefault();
}
onmouseup(ev) {
this.mousedown = false;
this.pixelthreshold();
ev.preventDefault();
}
onmousemove(e) {
const x = Math.round(e.clientX - this.c.getBoundingClientRect().left);
const y = Math.round(e.clientY - this.c.getBoundingClientRect().top);
// const x = ev.clientX;
// const y = ev.clientY;
if (this.mousedown) {
this.paint(x, y);
}
}
getpixelamount(r, g, b) {
const pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
const all = pixels.data.length;
let amount = 0;
for (let i = 0; i < all; i += 4) {
if (pixels.data[i] === r &&
pixels.data[i + 1] === g &&
pixels.data[i + 2] === b) {
amount++;
}
}
return amount;
}
drawletter(letter) {
const centerx = (this.c.width - this.cx.measureText(letter).width) / 2;
const centery = this.c.height / 2;
// this.cx.fillText(letter, centerx, centery);
// debugger
const path = new Path2D('M60.4248047,180.541992 C73.445638,180.541992 84.9405924,177.693685 94.909668,171.99707 C104.878743,166.300456 112.508138,158.610026 117.797852,148.925781 C123.087565,139.241536 125.732422,128.499349 125.732422,116.699219 C125.732422,108.561198 124.267578,100.952148 121.337891,93.8720703 C118.408203,86.7919922 114.379883,80.6681315 109.25293,75.5004883 C104.125977,70.3328451 98.1648763,66.2841797 91.3696289,63.3544922 C84.5743815,60.4248047 77.2705078,58.9599609 69.4580078,58.9599609 C59.6923828,58.9599609 49.0315755,62.0524089 37.4755859,68.2373047 L37.4755859,68.2373047 L44.4335938,28.6865234 L102.416992,28.6865234 C108.439128,28.6865234 112.996419,27.3844401 116.088867,24.7802734 C119.181315,22.1761068 120.727539,18.758138 120.727539,14.5263672 C120.727539,4.8421224 114.379883,0 101.68457,0 L101.68457,0 L37.2314453,0 C30.2327474,0 25.1871745,1.58691406 22.0947266,4.76074219 C19.0022786,7.93457031 16.8863932,13.0208333 15.7470703,20.0195312 L15.7470703,20.0195312 L5.49316406,78.4912109 C4.59798177,83.6181641 4.15039062,86.3850911 4.15039062,86.7919922 C4.15039062,90.4541016 5.69661458,93.7296549 8.7890625,96.6186523 C11.8815104,99.5076497 15.4215495,100.952148 19.4091797,100.952148 C23.0712891,100.952148 27.730306,98.815918 33.3862305,94.543457 C39.0421549,90.2709961 43.375651,87.2802734 46.3867188,85.5712891 C49.3977865,83.8623047 54.4026693,83.0078125 61.4013672,83.0078125 C67.0979818,83.0078125 72.265625,84.370931 76.9042969,87.097168 C81.5429688,89.8234049 85.2457682,93.9534505 88.0126953,99.4873047 C90.7796224,105.021159 92.1630859,111.694336 92.1630859,119.506836 C92.1630859,126.749674 90.8813477,133.219401 88.3178711,138.916016 C85.7543945,144.61263 82.1126302,149.088542 77.3925781,152.34375 C72.672526,155.598958 67.179362,157.226562 60.9130859,157.226562 C54.0771484,157.226562 47.8922526,155.212402 42.3583984,151.184082 C36.8245443,147.155762 32.430013,141.520182 29.1748047,134.277344 C25.8382161,126.383464 20.7519531,122.436523 13.9160156,122.436523 C9.92838542,122.436523 6.61214193,123.860677 3.96728516,126.708984 C1.32242839,129.557292 0,132.568359 0,135.742188 C0,140.950521 1.89208984,147.033691 5.67626953,153.991699 C9.46044922,160.949707 15.8894857,167.114258 24.9633789,172.485352 C34.0372721,177.856445 45.8577474,180.541992 60.4248047,180.541992 Z');
this.cx.translate(centerx, centery);
this.cx.stroke(path);
}
}
<canvas id=canvas></canvas>
I update my code, not problem insert SVG in canvas. I don't understand how to fill this by touch with animation like in example game.
new class Game {
constructor() {
this.c = document.querySelector('canvas')
this.cx = this.c.getContext('2d')
this.init()
this.c.addEventListener('mousedown', this.onmousedown.bind(this), false);
this.c.addEventListener('mouseup', this.onmouseup.bind(this), false);
this.c.addEventListener('mousemove', this.onmousemove.bind(this), false);
}
init() {
this.c.height = 190;
this.c.width = 140;
this.cx.fillStyle = 'rgb(200, 200, 250)';
this.drawletter('5');
this.cx.fillStyle = 'rgb(0, 0, 50)';
this.letterpixels = this.getpixelamount(200, 200, 250);
}
pixelthreshold() {
if (this.getpixelamount(0, 0, 50) / this.letterpixels > 0.75) {
console.log('you got it!');
}
}
showerror(error) {
this.mousedown = false;
console.log(error)
}
getpixelcolour(x, y) {
const pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
const index = ((y * (pixels.width * 4)) + (x * 4));
return {
r: pixels.data[index],
g: pixels.data[index + 1],
b: pixels.data[index + 2],
a: pixels.data[index + 3]
};
}
paint(x, y) {
const colour = this.getpixelcolour(x, y);
if (colour.a === 0) {
this.showerror('you are outside');
} else {
const fillRange = 20;
const stack = [[x, y]];
while (stack.length > 0) {
const pixel = stack.pop();
if (pixel[0] < 0 || pixel[0] >= this.c.width) continue;
if (pixel[1] < 0 || pixel[1] >= this.c.height) continue;
if(((x - pixel[0]) ** 2 + (y - pixel[1]) ** 2) ** .5 > fillRange) continue;
const color = this.getpixelcolour(...pixel);
if (color.a === 0) continue;
if (color.r === 0 && color.g === 0 && color.b === 50) continue;
this.cx.fillRect(pixel[0], pixel[1], 1, 1);
if(pixel[0] >= x) stack.push([pixel[0] + 1, pixel[1]]);
if(pixel[0] <= x) stack.push([pixel[0] - 1, pixel[1]]);
if(pixel[1] >= y) stack.push([pixel[0], pixel[1] + 1]);
if(pixel[1] <= y) stack.push([pixel[0], pixel[1] - 1]);
}
}
}
onmousedown(ev) {
this.mousedown = true;
ev.preventDefault();
}
onmouseup(ev) {
this.mousedown = false;
this.pixelthreshold();
ev.preventDefault();
}
onmousemove(e) {
const x = Math.round(e.clientX - this.c.getBoundingClientRect().left);
const y = Math.round(e.clientY - this.c.getBoundingClientRect().top);
if (this.mousedown) {
this.paint(x, y);
} else {
// console.log(this.getpixelcolour(x, y));
}
}
getpixelamount(r, g, b) {
const pixels = this.cx.getImageData(0, 0, this.c.width, this.c.height);
const all = pixels.data.length;
let amount = 0;
for (let i = 0; i < all; i += 4) {
if (pixels.data[i] === r && pixels.data[i + 1] === g && pixels.data[i + 2] === b) {
amount++;
}
}
return amount;
}
drawletter(letter) {
const path = new Path2D('M60.4248047,180.541992 C73.445638,180.541992 84.9405924,177.693685 94.909668,171.99707 C104.878743,166.300456 112.508138,158.610026 117.797852,148.925781 C123.087565,139.241536 125.732422,128.499349 125.732422,116.699219 C125.732422,108.561198 124.267578,100.952148 121.337891,93.8720703 C118.408203,86.7919922 114.379883,80.6681315 109.25293,75.5004883 C104.125977,70.3328451 98.1648763,66.2841797 91.3696289,63.3544922 C84.5743815,60.4248047 77.2705078,58.9599609 69.4580078,58.9599609 C59.6923828,58.9599609 49.0315755,62.0524089 37.4755859,68.2373047 L37.4755859,68.2373047 L44.4335938,28.6865234 L102.416992,28.6865234 C108.439128,28.6865234 112.996419,27.3844401 116.088867,24.7802734 C119.181315,22.1761068 120.727539,18.758138 120.727539,14.5263672 C120.727539,4.8421224 114.379883,0 101.68457,0 L101.68457,0 L37.2314453,0 C30.2327474,0 25.1871745,1.58691406 22.0947266,4.76074219 C19.0022786,7.93457031 16.8863932,13.0208333 15.7470703,20.0195312 L15.7470703,20.0195312 L5.49316406,78.4912109 C4.59798177,83.6181641 4.15039062,86.3850911 4.15039062,86.7919922 C4.15039062,90.4541016 5.69661458,93.7296549 8.7890625,96.6186523 C11.8815104,99.5076497 15.4215495,100.952148 19.4091797,100.952148 C23.0712891,100.952148 27.730306,98.815918 33.3862305,94.543457 C39.0421549,90.2709961 43.375651,87.2802734 46.3867188,85.5712891 C49.3977865,83.8623047 54.4026693,83.0078125 61.4013672,83.0078125 C67.0979818,83.0078125 72.265625,84.370931 76.9042969,87.097168 C81.5429688,89.8234049 85.2457682,93.9534505 88.0126953,99.4873047 C90.7796224,105.021159 92.1630859,111.694336 92.1630859,119.506836 C92.1630859,126.749674 90.8813477,133.219401 88.3178711,138.916016 C85.7543945,144.61263 82.1126302,149.088542 77.3925781,152.34375 C72.672526,155.598958 67.179362,157.226562 60.9130859,157.226562 C54.0771484,157.226562 47.8922526,155.212402 42.3583984,151.184082 C36.8245443,147.155762 32.430013,141.520182 29.1748047,134.277344 C25.8382161,126.383464 20.7519531,122.436523 13.9160156,122.436523 C9.92838542,122.436523 6.61214193,123.860677 3.96728516,126.708984 C1.32242839,129.557292 0,132.568359 0,135.742188 C0,140.950521 1.89208984,147.033691 5.67626953,153.991699 C9.46044922,160.949707 15.8894857,167.114258 24.9633789,172.485352 C34.0372721,177.856445 45.8577474,180.541992 60.4248047,180.541992 Z');
this.cx.fill(path);
}
}
<canvas id=canvas></canvas>
const ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
const svg = new Image();
svg.onload = () => ctx.drawImage(svg, 0, 0);
svg.src = "http://graphing.ru/examples/butterfly.svg";
<canvas id=canvas></canvas>

Converting jquery controls to javascript

So i am trying to implement simple touch controls on a javascript game. I have the following answer from a search:
Snake Game with Controller Buttons for Mobile Use **UPDATED**
However I was trying to change this jquery into javascript so that it would work with my game
Jquery:
$(document).on('click', '.button-pad > button', function(e) {
if ($(this).hasClass('left-btn')) {
e = 37;
}
Javascript:
var contoller = document.getElementById("button-pad").on('click',
'.button-pad > button', function(e) {
if ('.button-pad > button'(this).hasClass('btn-left')) {
e = 37;
}
I thought I had it sorted but it is not working at all
Codepen here:
https://codepen.io/MrVincentRyan/pen/VqpMrJ?editors=1010
Your existing code has some problems with it, but it was close enough where I could translate it. However, your current code seems to want to reassign the event argument being passed to the click handler (e) to 37. This makes no sense. Most likely you just want another variable set to 37 and that's what I've done below:
spaceInvader(window, document.getElementById('space-invader'));
window.focus();
let game = null;
let ship = null;
function spaceInvader (window, canvas) {
canvas.focus();
var context = canvas.getContext('2d');
/* GAME */
function Game () {
this.message = '';
this.rebel = [];
this.republic = [];
this.other = [];
this.size = {x: canvas.width, y: canvas.height};
this.wave = 0;
this.refresh = function () {
this.update();
this.draw();
requestAnimationFrame(this.refresh);
}.bind(this);
this.init();
}
Game.MESSAGE_DURATION = 1500;
Game.prototype.init = function () {
this.ship = new Ship(this);
this.addRebel(this.ship);
this.refresh();
};
Game.prototype.update = function () {
this.handleCollisions();
this.computeElements();
this.elements.forEach(Element.update);
if (!this.rebel.length) {
this.showText('Gatwick closed', true);
return;
}
if (!this.republic.length) this.createWave();
};
Game.prototype.draw = function () {
context.clearRect(0, 0, this.size.x, this.size.y);
this.elements.forEach(Element.draw);
Alien.drawLife(this.republic);
if (this.message) {
context.save();
context.font = '30px Arial';
context.textAlign='center';
context.fillStyle = '#FFFFFF';
context.fillText(this.message, canvas.width / 2, canvas.height / 2);
context.restore();
}
};
Game.prototype.computeElements = function () {
this.elements = this.other.concat(this.republic, this.rebel);
};
Game.prototype.addRebel = function (element) {
this.rebel.push(element);
};
Game.prototype.addRepublic = function (element) {
this.republic.push(element);
};
Game.prototype.addOther = function (element) {
this.other.push(element);
};
Game.prototype.handleCollisions = function () {
this.rebel.forEach(function(elementA) {
this.republic.forEach(function (elementB) {
if (!Element.colliding(elementA, elementB)) return;
elementA.life--;
elementB.life--;
var sizeA = elementA.size.x * elementA.size.y;
var sizeB = elementB.size.x * elementB.size.y;
this.addOther(new Explosion(this, sizeA > sizeB ? elementA.pos : elementB.pos));
}, this);
}, this);
this.republic = this.republic.filter(Element.isAlive);
this.rebel = this.rebel.filter(Element.isAlive);
this.other = this.other.filter(Element.isAlive);
this.republic = this.republic.filter(this.elementInGame, this);
this.rebel = this.rebel.filter(this.elementInGame, this);
};
Game.prototype.elementInGame = function (element) {
return !(element instanceof Bullet) || (
element.pos.x + element.halfWidth > 0 &&
element.pos.x - element.halfWidth < this.size.x &&
element.pos.y + element.halfHeight > 0 &&
element.pos.y - element.halfHeight < this.size.x
);
};
Game.prototype.createWave = function () {
this.ship.life = Ship.MAX_LIFE;
this.ship.fireRate = Math.max(50, Ship.FIRE_RATE - 50 * this.wave);
this.wave++;
this.showText('Wave: ' + this.wave);
var waveSpeed = Math.ceil(this.wave / 2);
var waveProb = (999 - this.wave * 2) / 1000;
var margin = {x: Alien.SIZE.x + 10, y: Alien.SIZE.y + 10};
for (var i = 0; i < 2; i++) {
var x = margin.x + (i % 8) * margin.x;
var y = -200 + (i % 3) * margin.y;
this.addRepublic(new Alien(this, {x: x, y: y}, waveSpeed, waveProb));
}
};
Game.prototype.showText = function (message, final) {
this.message = message;
if (!final) setTimeout(this.showText.bind(this, '', true), Game.MESSAGE_DURATION);
};
/* GENERIC ELEMENT */
function Element (game, pos, size) {
this.game = game;
this.pos = pos;
this.size = size;
this.halfWidth = Math.floor(this.size.x / 2);
this.halfHeight = Math.floor(this.size.y / 2);
}
Element.update = function (element) {
element.update();
};
Element.draw = function (element) {
element.draw();
};
Element.isAlive = function (element) {
return element.life > 0;
};
Element.colliding = function (elementA, elementB) {
return !(
elementA === elementB ||
elementA.pos.x + elementA.halfWidth < elementB.pos.x - elementB.halfWidth ||
elementA.pos.y + elementA.halfHeight < elementB.pos.y - elementB.halfHeight ||
elementA.pos.x - elementA.halfWidth > elementB.pos.x + elementB.halfWidth ||
elementA.pos.y - elementA.halfHeight > elementB.pos.y + elementB.halfHeight
);
};
/* SHIP */
function Ship(game) {
var pos = {
x: Math.floor(game.size.x / 2) - Math.floor(Ship.SIZE.x / 2),
y: game.size.y - Math.floor(Ship.SIZE.y / 2)
};
Element.call(this, game, pos, Ship.SIZE);
this.kb = new KeyBoard();
this.speed = Ship.SPEED;
this.allowShooting = true;
this.life = Ship.MAX_LIFE;
this.fireRate = Ship.FIRE_RATE;
}
Ship.SIZE = {x: 67, y: 100};
Ship.SPEED = 8;
Ship.MAX_LIFE = 5;
Ship.FIRE_RATE = 200;
Ship.prototype.update = function () {
if (this.kb.isDown(KeyBoard.KEYS.LEFT) && this.pos.x - this.halfWidth > 0) {
this.pos.x -= this.speed;
} else if (this.kb.isDown(KeyBoard.KEYS.RIGHT) && this.pos.x + this.halfWidth < this.game.size.x) {
this.pos.x += this.speed;
}
if (this.allowShooting && this.kb.isDown(KeyBoard.KEYS.SPACE)) {
var bullet = new Bullet(
this.game,
{x: this.pos.x, y: this.pos.y - this.halfHeight },
{ x: 0, y: -Bullet.SPEED },
true
);
this.game.addRebel(bullet);
this.toogleShooting();
}
};
Ship.prototype.draw = function () {
var img = document.getElementById('ship');
context.save();
context.translate(this.pos.x - this.halfWidth, this.pos.y - this.halfHeight);
context.drawImage(img, 0, 0);
context.restore();
this.drawLife();
};
Ship.prototype.drawLife = function () {
context.save();
context.fillStyle = 'white';
context.fillRect(this.game.size.x -112, 10, 102, 12);
context.fillStyle = 'red';
context.fillRect(this.game.size.x -111, 11, this.life * 100 / Ship.MAX_LIFE, 10);
context.restore();
};
Ship.prototype.toogleShooting = function (final) {
this.allowShooting = !this.allowShooting;
if (!final) setTimeout(this.toogleShooting.bind(this, true), this.fireRate);
};
/* ALIENS */
function Alien(game, pos, speed, shootProb) {
Element.call(this, game, pos, Alien.SIZE);
this.speed = speed;
this.shootProb = shootProb;
this.life = 3;
this.direction = {x: 1, y: 1};
}
Alien.SIZE = {x: 51, y: 60};
Alien.MAX_RANGE = 350;
Alien.CHDIR_PRO = 0.990;
Alien.drawLife = function (array) {
array = array.filter(function (element) {
return element instanceof Alien;
});
context.save();
context.fillStyle = 'white';
context.fillRect(10, 10, 10 * array.length + 2, 12);
array.forEach(function (alien, idx) {
switch (alien.life) {
case 3:
context.fillStyle = 'green';
break;
case 2:
context.fillStyle = 'yellow';
break;
case 1:
context.fillStyle = 'red';
break;
}
context.fillRect(10 * idx + 11, 11, 10, 10);
});
context.restore();
};
Alien.prototype.update = function () {
if (this.pos.x - this.halfWidth <= 0) {
this.direction.x = 1;
} else if (this.pos.x + this.halfWidth >= this.game.size.x) {
this.direction.x = -1;
} else if (Math.random() > Alien.CHDIR_PRO) {
this.direction.x = -this.direction.x;
}
if (this.pos.y - this.halfHeight <= 0) {
this.direction.y = 1;
} else if (this.pos.y + this.halfHeight >= Alien.MAX_RANGE) {
this.direction.y = -1;
} else if (Math.random() > Alien.CHDIR_PRO) {
this.direction.y = -this.direction.y;
}
this.pos.x += this.speed * this.direction.x;
this.pos.y += this.speed * this.direction.y;
if (Math.random() > this.shootProb) {
var bullet = new Bullet(
this.game,
{x: this.pos.x, y: this.pos.y + this.halfHeight },
{ x: Math.random() - 0.5, y: Bullet.SPEED },
false
);
this.game.addRepublic(bullet);
}
};
Alien.prototype.draw = function () {
var img = document.getElementById('fighter');
context.save();
context.translate(this.pos.x + this.halfWidth, this.pos.y + this.halfHeight);
context.rotate(Math.PI);
context.drawImage(img, 0, 0);
context.restore();
};
/* BULLET */
function Bullet(game, pos, direction, isRebel) {
Element.call(this, game, pos, Bullet.SIZE);
this.direction = direction;
this.isRebel = isRebel;
this.life = 1;
try {
var sound = document.getElementById('sound-raygun');
sound.load();
sound.play().then(function () {}, function () {});
}
catch (e) {
// only a sound issue
}
}
Bullet.SIZE = {x: 6, y: 20};
Bullet.SPEED = 3;
Bullet.prototype.update = function () {
this.pos.x += this.direction.x;
this.pos.y += this.direction.y;
};
Bullet.prototype.draw = function () {
context.save();
var img;
if (this.isRebel) {
context.translate(this.pos.x - this.halfWidth, this.pos.y - this.halfHeight);
img = document.getElementById('rebel-bullet');
}
else {
context.translate(this.pos.x + this.halfWidth, this.pos.y + this.halfHeight);
img = document.getElementById('republic-bullet');
context.rotate(Math.PI);
}
context.drawImage(img, 0, 0);
context.restore();
};
/* EXPLOSION */
function Explosion(game, pos) {
Element.call(this, game, pos, Explosion.SIZE);
this.life = 1;
this.date = new Date();
try {
var sound = document.getElementById('sound-explosion');
sound.load();
sound.play().then(function () {}, function () {});
}
catch (e) {
// only a sound issue
}
}
Explosion.SIZE = {x: 115, y: 100};
Explosion.DURATION = 150;
Explosion.prototype.update = function () {
if (new Date() - this.date > Explosion.DURATION) this.life = 0;
};
Explosion.prototype.draw = function () {
var img = document.getElementById('explosion');
context.save();
context.translate(this.pos.x - this.halfWidth, this.pos.y - this.halfHeight);
context.drawImage(img, 0, 0);
context.restore();
};
/* KEYBOARD HANDLING */
function KeyBoard() {
var state = {};
window.addEventListener('keydown', function(e) {
state[e.keyCode] = true;
});
window.addEventListener('keyup', function(e) {
state[e.keyCode] = false;
});
this.isDown = function (key) {
return state[key];
};
}
KeyBoard.KEYS = {
LEFT: 37,
RIGHT: 39,
SPACE: 32
};
window.addEventListener('load', function() {
game = new Game();
});
// Get all the button elements that are children of elements that have
// the .button-pad class and convert the resulting node list into an Array
let elements =
Array.prototype.slice.call(document.querySelectorAll('.button-pad button'));
// Loop over the array
elements.forEach(function(el){
el.textContent = "XXXX";
// Set up a click event handler for the current element being iterated:
el.addEventListener('click', function(e) {
// When the element is clicked, check to see if it uses the left-btn class
if(this.classList.contains('left-btn')) {
// Perform whatever actions you need to:
ship.update();
}
});
});
}
<h1>Gatwick invaders</h1>
<p>Press <b>left arrow</b> to go left, <b>right arrow</b> to go right, and <b>space</b> to shoot...</p>
<canvas id="space-invader" width="640" height="500" tabindex="0"></canvas>
<img id="fighter" src="https://raw.githubusercontent.com/MrVIncentRyan/assets/master/drone1.png" />
<img id="ship" src="https://raw.githubusercontent.com/MrVIncentRyan/assets/master/cop1.png" />
<img id="rebel-bullet" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/rebelBullet.png" />
<img id="republic-bullet" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/republicBullet.png" />
<img id="explosion" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/explosion.png" />
<audio id="sound-explosion" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/explosion.mp3"></audio>
<audio id="sound-raygun" src="https://raw.githubusercontent.com/OlivierB-OB/starwars-invader/master/raygun.mp3"></audio>
</div>
<div class="button-pad">
<div class="btn-up">
<button type="submit" class="up">
<img src="http://aaronblomberg.com/sites/ez/images/btn-up.png" />
</button>
</div>
<div class="btn-right">
<button type="submit" class="right">
<img src="http://aaronblomberg.com/sites/ez/images/btn-right.png" />
</button>
</div>
<div class="btn-down">
<button type="submit" class="down">
<img src="http://aaronblomberg.com/sites/ez/images/btn-down.png" />
</button>
</div>
<div class="btn-left">
<button type="submit" class="left">
<img src="http://aaronblomberg.com/sites/ez/images/btn-left.png" />
</button>
</div>
</div>
A custom solution for emulating keypresses on mobile in both vanilla Javascript as well as jQuery!
// jQuery (edge), for use with ES2015-19
/*
$(document).on("click", ".example-btn", e => { // Click event handler
if($(this).hasClass("example-btn")) { // Verifying that element has class
e = 37
jQuery.event.trigger({type: "keypress", which: character.charCodeAt(e)}) // Simulating keystroke
// The following is simply for debugging, remove if needed
alert("Button validation confirmed!")
console.log("E: ", e)
}
})
*/
// Pure Javascript (ECMA Standard)
document.querySelector(".example-btn").addEventListener("click", function(e) { // Click event handler
if(this.classList.contains("example-btn")) { // Verifying that element has class
e = 37
if(document.createEventObject) {
var eventObj = document.createEventObject();
eventObj.keyCode = e;
document.querySelector(".example-btn").fireEvent("onkeydown", eventObj);
} else if(document.createEvent) {
var eventObj2 = document.createEvent("Events");
eventObj2.initEvent("keydown", true, true);
eventObj2.which = e;
document.querySelector(".example-btn").dispatchEvent(eventObj2);
}
// The following is simply for debugging, remove if needed
alert("Button validation confirmed!");
console.log("E: ", e);
}
});
// ---------------------------------------------------------------------------------------------------
/*
You can not use the "this" statement when referring to an embedded element. In your previous code "this" would refer to ".button-container > .example-btn" which the compiler will interpret as only the parent element, being .button-container (.button-pad in your code) not the child element in which you want. Also there is no such thing as returning a character code and expecting it to automatically know what to do with it. I assume you are doing this to emulate a keystroke on a mobile device and I assure you that this design works although it might be flawed. Give it a try and I hope it does something to at least help if not solve your problem.
*/
// ---------------------------------------------------------------------------------------------------
When an event listener is attached to an element, that listener is not unique for the element, but it propagates to its children.
This functionality is enabled in jQuery by adding a parameter on an event listener a parameter that targets the element that we want.
This is not case in vanillaJS, but using e.target we can inspect in which elements the event is executed.
Probably your are looking something like this. However, I would prefer to add an id in the button so you can more easily work with it.
document.addEventListener('click', function(e){
if(e.target.tagName === 'BUTTON' && e.target.classList.value.includes('btn-left')){
// execute your code
}
});

Categories

Resources