I am making a virtual open when website with the P5 library. I have to make it compatible with phones.I have added the invisibility feature to test it. I know how to add one-touch but how do I multiple touches as this requires multiple touches?
Here is my code
var laugh, laughI, sadI, sad, titleI, title, annoyI, annoy, motiI, moti
var stressI, stress, angryI, angry;
function preload(){
laughI = loadImage("images/laugh.png");
sadI = loadImage("images/sad.png");
titleI = loadImage("images/title.png");
annoyI = loadImage("images/annoy.png");
motiI = loadImage("images/motivation.png");
stressI = loadImage("images/stress.png");
angryI = loadImage("images/angry.png");
}
function setup() {
createCanvas(windowWidth, 1800);
title = createSprite(windowWidth/2, 80)
title.addImage(titleI)
title.scale = 0.9;
laugh = createSprite(windowWidth/2, 270);
laugh.addImage(laughI);
laugh.scale = 0.2;
sad = createSprite(windowWidth/2, 550);
sad.addImage(sadI);
sad.scale = 0.2;
annoy = createSprite(windowWidth/2, 830);
annoy.addImage(annoyI);
annoy.scale = 0.2;
moti = createSprite(windowWidth/2, 1110);
moti.addImage(motiI);
moti.scale = 0.2;
stress = createSprite(windowWidth/2, 1390);
stress.addImage(stressI);
stress.scale = 0.2;
angry = createSprite(windowWidth/2, 1670);
angry.addImage(angryI);
angry.scale = 0.2;
}
function draw() {
background(0);
if(mouseIsPressed){
laugh.visible = false;
}
drawSprites();
}
On a phone I believe you will get the mousePressed() event if a user taps, and mouseIsPressed should be set to true when a touch happens (at least until the number of touches decreases). However you can also explicitly check for touches with the touches array.
function setup() {
createCanvas(windowWidth, windowHeight);
// Prevent top level gesture scrolling/zooming
// This if iOS Safari specific
document.addEventListener("gesturestart", function (e) {
e.preventDefault();
return false;
});
}
let pressedAt;
let clickedAt;
function mousePressed(e) {
pressedAt = frameCount;
}
function mouseClicked(e) {
clickedAt = frameCount;
}
function draw() {
background(220);
if (frameCount - clickedAt < 30) {
background("orange");
} else if (frameCount - pressedAt < 30) {
background("blue");
} else {
if (touches.length) {
background("green");
text(`${mouseIsPressed ? 'mouse pressed' : 'mouse not pressed'} (touches: ${touches.length})`, 10, height / 2);
} else if (mouseIsPressed) {
background("red");
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
Since snippets don't work on mobile, you can run the example here: https://editor.p5js.org/Kumu-Paul/full/LpkV7Gio2
Related
I coded a little simulation where you can dig cubes, they fall an stack, you can consume some or make a selection explode.
I started this little project for fun and my aim is to handle as much cubes as possible (100k would be a good start).
The project is simple, 3 possibles actions:
Dig cubes (2k each click)
Consume cubes (50 each click)
Explode cubes (click on two points to form a rectangle)
Currently, on my computer, performance starts to drop when I got about 20k cubes. When you select a large portion of cubes to explode, performance are heavily slowed down too. I'm not sure the way I simplified physics is the best way to go.
Could you give me some hints on how to improve/optimize it ?
Here is the complete code : (The stacking doesn't work in the SO snippet so here is the codepen version)
(() => {
// Variables init
let defaultState = {
cubesPerDig : 2000,
cubesIncome : 0,
total : 0
};
let cubeSize = 2, dropSize = window.innerWidth, downSpeed = 5;
let state,
digButton, // Button to manually dig
gameState, // An object containing the state of the game
cubes, // Array containing all the spawned cubes
heightIndex, // fake physics
cubesPerX, // fake physics helper
playScene; // The gamescene
// App setup
let app = new PIXI.Application();
app.renderer.view.style.position = "absolute";
app.renderer.view.style.display = "block";
app.renderer.autoResize = true;
document.body.appendChild(app.view);
// Resize
function resize() {
app.renderer.resize(window.innerWidth, window.innerHeight);
}
window.onresize = resize;
resize();
// Hello ! we can talk in the chat.txt file
// Issue : When there are more than ~10k cubes, performance start to drop
// To test, click the "mine" button about 5-10 times
// Main state
function play(delta){
// Animate the cubes according to their states
let cube;
for(let c in cubes){
cube = cubes[c];
switch(cube.state) {
case STATE.LANDING:
// fake physics
if(!cube.landed){
if (cube.y < heightIndex[cube.x]) {
cube.y+= downSpeed;
}else if (cube.y >= heightIndex[cube.x]) {
cube.y = heightIndex[cube.x];
cube.landed = 1;
heightIndex[cube.x] -= cubeSize;
}
}
break;
case STATE.CONSUMING:
if(cube.y > -cubeSize){
cube.y -= cube.speed;
}else{
removeCube(c);
}
break;
case STATE.EXPLODING:
if(boundings(c)){
continue;
}
cube.x += cube.eDirX;
cube.y += cube.eDirY;
break;
}
}
updateUI();
}
// Game loop
function gameLoop(delta){
state(delta);
}
// Setup variables and gameState
function setup(){
state = play;
digButton = document.getElementById('dig');
digButton.addEventListener('click', mine);
playScene = new PIXI.Container();
gameState = defaultState;
/* User inputs */
// Mine
document.getElementById('consume').addEventListener('click', () => {consumeCubes(50)});
// Manual explode
let explodeOrigin = null
document.querySelector('canvas').addEventListener('click', e => {
if(!explodeOrigin){
explodeOrigin = {x: e.clientX, y: e.clientY};
}else{
explode(explodeOrigin, {x: e.clientX, y: e.clientY});
explodeOrigin = null;
}
});
window['explode'] = explode;
heightIndex = {};
cubesPerX = [];
// Todo fill with gameState.total cubes
cubes = [];
app.ticker.add(delta => gameLoop(delta));
app.stage.addChild(playScene);
}
/*
* UI
*/
function updateUI(){
document.getElementById('total').innerHTML = cubes.length;
}
/*
* Game logic
*/
// Add cube when user clicks
function mine(){
for(let i = 0; i < gameState.cubesPerDig; i++){
setTimeout(addCube, 5*i);
}
}
// Consume a number of cubes
function consumeCubes(nb){
let candidates = _.sampleSize(cubes.filter(c => !c.eDirX), Math.min(nb, cubes.length));
candidates = candidates.slice(0, nb);
candidates.map(c => {
dropCubes(c.x);
c.state = STATE.CONSUMING;
});
}
const STATE = {
LANDING: 0,
CONSUMING: 1,
EXPLODING: 2
}
// Add a cube
function addCube(){
let c = new cube(cubeSize);
let tres = dropSize / cubeSize / 2;
c.x = window.innerWidth / 2 + (_.random(-tres, tres) * cubeSize);
c.y = 0//-cubeSize;
c.speed = _.random(5,8);
cubes.push(c);
c.landed = !1;
c.state = STATE.LANDING;
if(!cubesPerX[c.x]) cubesPerX[c.x] = [];
if (!heightIndex[c.x]) heightIndex[c.x] = window.innerHeight - cubeSize;
cubesPerX[c.x].push(c);
playScene.addChild(c);
}
// Remove a cube
function removeCube(c){
let cube = cubes[c];
playScene.removeChild(cube);
cubes.splice(c,1);
}
// Delete the cube if offscreen
function boundings(c){
let cube = cubes[c];
if(cube.x < 0 || cube.x + cubeSize > window.innerWidth || cube.y < 0 || cube.y > window.innerHeight)
{
removeCube(c);
return true;
}
}
// explode some cubes
function explode(origin, dest){
if(dest.x < origin.x){
dest = [origin, origin = dest][0]; // swap
}
var candidates = cubes.filter(c => c.state != STATE.EXPLODING && c.x >= origin.x && c.x <= dest.x && c.y >= origin.y && c.y <= dest.y);
if(!candidates.length)
return;
for(let i = origin.x; i <= dest.x; i++){
dropCubes(i);
}
candidates.forEach(c => {
c.explodingSpeed = _.random(5,6);
c.eDirX = _.random(-1,1,1) * c.explodingSpeed * c.speed;
c.eDirY = _.random(-1,1,1) * c.explodingSpeed * c.speed;
c.state = STATE.EXPLODING;
});
}
// Drop cubes
function dropCubes(x){
heightIndex[x] = window.innerHeight - cubeSize;
if(cubesPerX[x] && cubesPerX[x].length)
cubesPerX[x].forEach(c => {
if(c.state == STATE.EXPLODING) return;
c.landed = false; c.state = STATE.LANDING;
});
}
/*
* Graphic display
*/
// Cube definition
function cube(size){
let graphic = new PIXI.Graphics();
graphic.beginFill(Math.random() * 0xFFFFFF);
graphic.drawRect(0, 0, size, size);
graphic.endFill();
return graphic;
}
// Init
setup();
})()
/* styles */
/* called by your view template */
* {
box-sizing: border-box;
}
body, html{
margin: 0;
padding: 0;
color:white;
}
#ui{
position: absolute;
z-index: 2;
top: 0;
width: 0;
left: 0;
bottom: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.1/pixi.min.js"></script>
<script>PIXI.utils.skipHello();</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
<!-- Click two points to make cubes explode -->
<div id="ui">
<button id="dig">
Dig 2k cubes
</button>
<button id="consume">
Consume 50 cubes
</button>
<p>
Total : <span id="total"></span>
</p>
</div>
Thanks
Using Sprites will always be faster than using Graphics (at least until v5 comes along!)
So I changed your cube creation function to
function cube(size) {
const sprite = new PIXI.Sprite(PIXI.Texture.WHITE);
sprite.tint = Math.random() * 0xFFFFFF;
sprite.width = sprite.height = size;
return sprite;
}
And that boosted the fps for myself
I have created multiple html5 canvas using instantiation mode in P5JS. I am using Neurosky mindwave EEG sensor to activate and deactivate canvas one by one. Neurosky mindwave EEG sensor can detect user's eye blink which I am using as input. When user blinks, it should activate one canvas and deactivate another canvas and vice-versa.I am using Neurosky mindwave EEG sensor to activate and deactivate canvas one by one. Neurosky mindwave EEG sensor can detect user's eye blink which I am using as input. When user blinks, it should activate one canvas and deactivate another canvas and vice-versa.
Just to check if my code logic works, I used mouse pressed input to switch between the canvas and it worked perfectly. But, when I used it with the sensor it didn't work.
What I did - I have created multiple HTML5 canvas using instantiation mode in P5JS. I have used node-neurosky node module to capture the eyeblink data from the sensor. Node Module
What worked - When I launch the app it takes the eye blink as input for the first time and activate the another canvas but when I blink again it doesn't deactivate the current canvas and activate another canvas. I have tried printing flags to check the code and it is doing fine. Eyeblink gets detected every time when I blink but it doesn't switch the canvas.
What didn't work - When I tried to use eye blink strength directly into the sketch.js it didn't work then I created another boolean variable eyeclick which also didn't work.
sketch.js
var stateTwo, stateOne = true;
// sketch one -----------------------------------
var first = new p5(firstSketch, "canvasOne");
function firstSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(255, 10, 100);
p.fill(255);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (eyeclicked) {
stateOne = false;
stateTwo = true;
console.log(" canvas <-- one");
// k = 0;
eyeclicked = false;
}
if (stateOne) {
$('#canvasOne').css('opacity', '1');
$('#canvasTwo').css('opacity', '0.5');
// console.log("canvas One");
p.fill(255, 0, 0);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
// sketch two -----------------------------------
var second = new p5(secondSketch, "canvasTwo");
function secondSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(60, 250, 100);
p.fill(0);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (eyeclicked) {
stateOne = true;
stateTwo = false;
console.log(" canvas <-- two");
// k = 0;
eyeclicked = false;
}
if (stateTwo) {
$('#canvasOne').css('opacity', '0.5');
$('#canvasTwo').css('opacity', '1');
// console.log("canvas Two");
p.fill(0, 0, 255);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
NodeCode to connect with sensor connect.js
var attention = 0;
var meditation = 0;
var blink;
var poorSignalLevel = 0;
var eyeclicked = false;
if ("WebSocket" in window) {
console.log("WebSocket is supported by your Browser. Proceed.");
// $('#connect-controls').show();
}
var ws = new WebSocket("ws://127.0.0.1:8080");
ws.onopen = function() {
console.log('opened connection');
ws.send("Hello from websocket client!");
};
// whenever websocket server transmit a message, do this stuff
ws.onmessage = function(evt) {
// parse the data (sent as string) into a standard JSON object (much easier to use)
var data = JSON.parse(evt.data);
// handle "eSense" data
if (data.eSense) {
$('#brain').css({
opacity: 1
});
attention = data.eSense.attention;
meditation = data.eSense.meditation;
// brainProgress('#focusProgress', attention);
// brainProgress('#medProgress', meditation);
$("#focus").text(attention);
$("#meditation").text(meditation);
}
// handle "blinkStrength" data
if (data.blinkStrength) {
blink = data.blinkStrength;
var blinkcol = "white";
var eyeVal = map_range(blink, 0, 255, 0, 100);
$('#eyeBlinkStrength').text(parseInt(eyeVal));
if (blink > 40) {
//blinkcol = "rgba(102,211,43,1.0)";
eyeclicked = true;
// k++;
console.log(blink + " " + eyeclicked);
} else blinkcol = "white";
$('#eyeBlink').css({
width: eyeVal,
height: eyeVal,
background: blinkcol
});
} else {
blink = 0;
eyeclicked = false;
}
// handle "poorSignal" data
if (data.poorSignalLevel != null) {
poorSignalLevel = parseInt(data.poorSignalLevel);
}
};
// when websocket closes connection, do this stuff
ws.onclose = function() {
// websocket is closed.
console.log("Connection is closed...");
};
function map_range(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
EDIT CODE PEN DEMO
Mouse Input Based Code which demonstrate the logic of switching between multiple canvas. It works perfectly. Try to click into the center circle
var stateTwo, stateOne = true;
var eyeIsBlinked;
// sketch one -----------------------------------
var first = new p5(firstSketch, "canvasOne");
function firstSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(255, 10, 100);
p.fill(255);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (p.mouseIsPressed && p.dist(p.mouseX, p.mouseY, p.width / 2, p.height / 2) < 50) {
stateOne = false;
stateTwo = true;
console.log(" <-- one");
// k = 0;
// window.eyeIsBlinked = false;
// blink = 0;
}
if (stateOne) {
$('#canvasOne').css('opacity', '1');
$('#canvasTwo').css('opacity', '0.5');
// console.log("canvas One");
p.fill(255, 0, 0);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
// sketch two -----------------------------------
var second = new p5(secondSketch, "canvasTwo");
function secondSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(60, 250, 100);
p.fill(0);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (p.mouseIsPressed && p.dist(p.mouseX, p.mouseY, p.width / 2, p.height / 2) < 50) {
stateOne = true;
stateTwo = false;
console.log(" <-- two");
// k = 0;
// window.eyeIsBlinked = false;
//blink = 0;
}
if (stateTwo) {
$('#canvasOne').css('opacity', '0.5');
$('#canvasTwo').css('opacity', '1');
// console.log("canvas Two");
p.fill(0, 0, 255);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
I don't know how your project works. But I guess the problem might be a scope problem. Both files are using the eyeclicked variable, but they might be using two different variables. Try to make sure that they're using the same variable by using it inside the window global variable.
So instead of eyeclicked use window.eyeclicked.
I have it so that when you (the PaintBrush) hit the finish everything clears and a button appears. When the button is clicked it starts level two, here it creates a new canvas. I've added some code so that when the button is clicked the old canvas is deleted, then the new one is made. However, this requires the canvas to have an id. how do i get this code:
canvas: document.createElement("canvas"),
To also include an id for it? I cannot have it say var canvas = blah blah and then have
canvas.id = "canvas";
because of the way i have it set up.
P.S the remove code is this if you need to know:
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = this.length - 1; i >= 0; i--) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
and in the button "click" function area i put this for the remove:
document.getElementById("canvas").remove();
Please help! Thanks in Advance!
EDIT: Here is some extra code to help, it is what occurs when the PaintBrush hits the finish:
else if (PaintBrush.crashWith(Finish)) {
PaintBrush.y = 50;
var button = document.createElement("button");
button.innerHTML = "Level 3";
button.id = "button-2"; // add the id to the button
document.body.appendChild(button); // append to body
GameArena2.clear();
GameArena2.stop();
button.addEventListener ("click", function() {
startGame2();
document.getElement("canvas").remove();
document.getElementById("button-2").remove();
});
EDIT 2: Game canvas code:
var GameArena2 = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 1280;
this.canvas.height = 480;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea2, 20);
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
},
drawGameOver: function() {
ctx2 = GameArena2.context;
ctx2.fillStyle = "rgba(0,0,0,"+fader +")";
ctx2.fillRect(0,0,GameArena2.width,GameArena2.height);
drawStatic(fader/2);
fader += .1 * 1/fps
ctx2.fillStyle = "rgba(255,255,255," + fader + ")";
ctx2.font = "72px sans-serif";
ctx2.fillText("GAME OVER",GameArena2.width/2 - 220,GameArena2.height/2);
}
}
function everyinterval(n) {
if ((GameArena.frameNo / n) % 1 == 0) {
return true;
}
else if ((GameArena.frameNo / n) % 1 == 0) {
return true;
}
return false;
}
I think the best way is to create a static function like this:
function createElementOnDom (type,id) {
var element=document.createElement(type);
element.id=id;
return element;
}
console.log(createElementOnDom('CANVAS','myId'));
So you can simply create the canvas adding it his specific id using a simple single row function call like you need.
I only know a way to do direcly this on jQuery, that you wouldn't like to use.
simply you need to do that:
function createElementOnDom (type,id) {
var element=document.createElement(type);
element.id=id;
return element;
}
var GameArena2 = {
canvas: createElementOnDom('CANVAS','myId'),
Simple! Just assign it immediately after the GameArena2 object is created.
var GameArena2 = {
canvas: document.createElement("canvas"),
start: function() {
...
...
}
// give id to a canvas
GameArena2.canvas.id = "GameArena2";
function everyinterval(n) {
if ((GameArena.frameNo / n) % 1 == 0) {
...
...
}
I have designed an HTML5 Game with a square that shoots at other squares. You have a certain amount of lives and gain a score. How do I prevent users from going into the console and doing something like this:
score=5000
planetHealth=200
Code to Game
$(document).ready(function() {
initStars(600);
});
var FPS = 60;
width = 300;
height = 400;
var gBackground = document.getElementById("canvas_background").getContext("2d");
var gPlayer = document.getElementById("canvas_player").getContext("2d");
var gEnemies = document.getElementById("canvas_enemies").getContext("2d");
var GUI = document.getElementById("canvas_ui").getContext("2d");
var bullets = [];
var enemies = [];
var shootTimer = 0;
var maxShootTimer = 15;
var score = 0;
var planetHealth = 50;
var gameState = "menu";
var Key = {
up: false,
down: false,
left: false,
right: false
};
var player = {
width: 16,
height: 16,
x: (width / 2) - 8,
speed: 3,
y: height - 20,
canShoot: true,
render: function() {
gPlayer.fillStyle="#24430A";
gPlayer.fillRect(this.x,this.y,this.width,this.height);
},
tick: function() {
if(Key.left && this.x > 0) this.x -= this.speed;
if(Key.right && this.x < width - 20) this.x += this.speed;
if(Key.space && this.canShoot) {
this.canShoot = false;
bullets.push(new Bullet(this.x,this.y - 4));
bullets.push(new Bullet(this.x + this.width,this.y - 4));
shootTimer = maxShootTimer;
}
}
};
stars = [];
addEventListener("keydown", function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.which;
switch(keyCode) {
case 38: // up
Key.up = true;
break;
case 40: // down
Key.down = true;
break;
case 37: // left
Key.left = true;
break;
case 39: // right
Key.right = true;
break;
case 32: //spacebar
Key.space = true;
break;
}
}, false);
addEventListener("keyup", function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.which;
switch(keyCode) {
case 38: // up
Key.up = false;
break;
case 40: // down
Key.down = false;
break;
case 37: // left
Key.left = false;
break;
case 39: // right
Key.right = false;
break;
case 32: //spacebar
Key.space = false;
break;
}
}, false);
function collision(obj1,obj2) {
return (
obj1.x < obj2.x+obj2.width &&
obj1.x + obj1.width > obj2.x &&
obj1.y < obj2.y+obj2.height &&
obj1.y + obj1.height > obj2.y
);
}
function Star(x,y) {
this.x = x;
this.y = y;
this.size = Math.random() * 2.5;
this.render = function() {
gBackground.fillStyle = "white";
gBackground.fillRect(this.x,this.y,this.size,this.size)
};
this.tick = function() {
this.y++;
}
}
function createStars(amount) {
for(i=0;i<amount;i ++) {
stars.push(new Star(Math.random() * width, -5));
}
}
function initStars(amount) {
for(i=0;i<amount;i++) {
stars.push(new Star(Math.random()*width,Math.random()*height));
}
}
function Bullet(x,y) {
this.x = x;
this.y = y;
this.width = 2;
this.height = 12;
this.speed = 3;
this.render = function() {
gPlayer.fillStyle = "red";
gPlayer.fillRect(this.x,this.y,this.width,this.height);
};
this.tick = function() {
if(this.y < -this.height) {
var index = bullets.indexOf(this);
bullets.splice(index,1);
}
this.y-=this.speed;
for(i in enemies) {
if(collision(this,enemies[i])) {
score = score + 50;
GUI.clearRect(0,0,width,height);
GUI.fillStyle ="white";
GUI.textBaseline = "top";
GUI.font = "bold 14px Tahoma";
GUI.fillText("Score: " + score, 2,2);
GUI.fillText("Lives: " + planetHealth, 2,16);
var enemyIndex = enemies.indexOf(enemies[i]);
enemies.splice(enemyIndex,1);
var bulletIndex = bullets.indexOf(this);
bullets.splice(bulletIndex,1);
}
}
};
}
function Enemy(x,y) {
this.x = x;
this.y = y;
this.width = 16;
this.height = 16;
this.speed = 0.5;
;
this.render = function() {
gEnemies.fillStyle = "red";
gEnemies.fillRect(this.x,this.y,this.width,this.height);
};
this.tick = function() {
if(this.y > this.height + height) {
this.y = -this.height;
planetHealth--;
GUI.clearRect(0,0,width,height);
GUI.fillStyle ="white";
GUI.textBaseline = "top";
GUI.font = "bold 14px Tahoma";
GUI.fillText("Score: " + score, 2,2);
GUI.fillText("Lives: " + planetHealth, 2,16);
}
this.y += this.speed;
}
}
for(x=0;x<8;x++) {
for(y=0;y<8;y++) {
enemies.push(new Enemy((x*24)+(width/2)-100,y*24));
}
}
function render() {
if(gameState == "play") {
gBackground.clearRect(0,0,width,height);
gPlayer.clearRect(0,0,width,height);
gEnemies.clearRect(0,0,width,height);
player.render();
for(i in stars) {
stars[i].render();
}
for(i in enemies) enemies[i].render();
for(i in bullets) bullets[i].render();
} else if(gameState == "gameOver") {
gBackground.clearRect(0,0,width,height);
for(i in stars) {
stars[i].render();
}
GUI.fillStyle = "white";
GUI.font = "bold 24px Tahoma";
GUI.fillText("You're a loser!", width / 2 - 100, height/2);
gEnemies.clearRect(0,0,width,height);
gPlayer.clearRect(0,0,width,height);
} else if(gameState == "gameWin") {
gBackground.clearRect(0,0,width,height);
for(i in stars) {
stars[i].render();
}
GUI.fillStyle = "white";
GUI.font = "bold 24px Tahoma";
GUI.fillText("You're a winner!", width / 2 - 100, height/2);
gEnemies.clearRect(0,0,width,height);
gPlayer.clearRect(0,0,width,height);
} else if(gameState == "menu") {
gBackground.clearRect(0,0,width,height);
for(i in stars) {
stars[i].render();
}
GUI.fillStyle = "white";
GUI.font = "bold 24px Tahoma";
GUI.fillText("Space Game!", width / 2 - 100, height/2);
GUI.font= "normal 16px Tahoma";
GUI.fillText("Press space to start", width / 2 - 90, (height/2)+28);
}
}
if(gameState == "play") {
GUI.fillStyle ="white";
GUI.textBaseline = "top";
GUI.font = "bold 14px Tahoma";
GUI.fillText("Score: " + score, 2,2);
GUI.fillText("Lives: " + planetHealth, 2,16);
}
function tick() {
createStars(1);
for(i in stars) stars[i].tick();
if(gameState == "play") {
if(planetHealth <= 0) gameState = "gameOver";
if(enemies.length <= 0) gameState = "gameWin";
player.tick();
for(i in enemies) enemies[i].tick();
for(i in bullets) bullets[i].tick();
if(shootTimer <= 0) player.canShoot = true;
shootTimer--;
} else if(gameState == "menu") {
if(Key.space) {
gameState = "play";
GUI.clearRect(0,0,width,height);
}
}
}
setInterval(function() {
render();
tick();
}, 1000/FPS );
<!DOCTYPE html>
<html>
<head>
<title> Game </title>
<style>
canvas {
position: absolute;
top: 0;
left: 0;
}
#canvas_background {
background: black;
}
</style>
</head>
<body>
<canvas id='canvas_background' width='300' height='400'></canvas>
<canvas id='canvas_player' width='300' height='400'></canvas>
<canvas id='canvas_enemies' width='300' height='400'></canvas>
<canvas id='canvas_ui' width='300' height='400'></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script src='game.js'></script>
</body>
</html>
You can't prevent a user from tampering with the console and the browser's dev tools gives you a lot of ways to take a peek anywhere in the code, even in closures as well as minified code.
But... you could make it harder.
First, you could do it like Facebook and just print a big red warning in the console saying "You shouldn't be here". We're essentially just scaring off the user, really.
Another option is to wrap the code in a closure, that way it's not exposed in the global scope. This avoids direct manipulation via the console.
;(function(){
// all code in here
());
Making it a bit harder is to use a minifier and an obfuscator.
The main purpose of a minifier is to shave file size by renaming names and rewriting code in a shorter way. The side effect is that the code becomes hard to read as most of the time it won't have any resemblance to your original code. It's worse without a source map and may take hours to trace and understand.
An obfuscator rewrites your code in a way that it still runs the same, just written in a different and often non-readable way. They even go as far as encoding the rewritten code in base64. For those who don't know what base64 is, they're good as gone.
Again, we're just making your code a bit harder to reach, fending off wannabe "hackers".
A more fool-proof way would be to just validate off-page, like on the server and use a variety of methods to determine tampered data. Games like speed typing impose a max score at a certain length of time since we all know we can't type a million words a second. Some games involve data analysis, if the data looks out of the ordinary.
You don't. If your game is entirely client-side, then you can't really stop players from cheating. You could make it more difficult with code obfuscation or taking variables out of the global scope, but that won't stop people who really want to cheat.
If players are connecting to a server for multiplayer or whatever you could implement server-side checks, since the users won't be able to touch that code.
You're running your code on the main scope of the Javascript, which is window.
When you create a global varable, this variable is scoped in the window object.
For that reason you can do this:
var a = 1;
console.log(a); // 1
console.log(window.a); // 1
It's very easy to avoid this, using the famous IIFE, which stands for Immediately Invoked Function Expression. You can read it at MDN.
Is just do this:
(function() {
// put all your code inside here
})();
When you do this, all the variable decladed inside that function, will be contained to the scope of that function.
But be aware, you can't prevent user cheating the game, you can only make it harder.
I'm making a sidescroller using Phaser (latest version) and I want the player's projectiles to go towards the pointer when the player clicks, like they do in this example http://phaser.io/examples/v2/games/tanks. I've used some of the code from the example but in my game, the activePointer x and y co-ordinates seem to only initialise when the game starts and never change. So when the player shoots, it's always going towards the same co-ordinates.
I have the following code (note I have removed bits about item collection, enemies etc. for posting on here):
var SideScroller = SideScroller || {};
var startPosX = 100;
var startPosY = 300;
var shooter;
var playerBullets;
var nextFire = 0;
var fireRate = 100;
var cursors;
var currentLoc;
SideScroller.Game = function () {};
SideScroller.Game.prototype = {
create: function () {
//create player
//params = (game, startPositionX,startPositionY, key, frame)
this.player = this.game.add.sprite(startPosX, startPosY, 'player');
//get canvas width and height for later use
canvasWidth = this.game.canvas.width;
canvasHeight = this.game.canvas.height;
//create enemy
var x = this.game.rnd.between(80, this.game.world.width);
var y = this.game.rnd.between(0, 113);
// Point to shoot projectiles from
// allows rotation, if this had been done on the player object, the graphic would have rotated, which we don't want
this.shooter = this.game.add.sprite(startPosX, startPosY, 'blank');
this.shooter.anchor.setTo(0.5, 0.5);
//make a group of player projectiles
playerBullets = this.game.add.group();
playerBullets.enableBody = true;
playerBullets.physicsBodyType = Phaser.Physics.ARCADE;
playerBullets.createMultiple(1000, 'peePower');
playerBullets.setAll('anchor.x', 0.5);
playerBullets.setAll('anchor.y', 0.5);
playerBullets.setAll('outOfBoundsKill', true);
playerBullets.setAll('checkWorldBounds', true);
//enable physics on the player
this.game.physics.arcade.enable(this.player);
//bring player shooting point to the top (not totally necessary)
this.shooter.bringToTop();
//player gravity
this.player.body.gravity.y = gravity;
//player collides with all four edges of the game world
this.player.body.collideWorldBounds = true;
this.player.anchor.setTo(0.5, 0.5);
//the camera will follow the player in the world
this.game.camera.follow(this.player);
//move player with cursor keys
cursors = this.game.input.keyboard.createCursorKeys();
},
update: function () {
currentLoc = this.game.input.activePointer;
//collision between player and platforms
this.game.physics.arcade.collide(this.player, this.blockedLayer, null, null, this);
//make co-ordinates match
this.shooter.x = this.player.x;
this.shooter.y = this.player.y;
//this.shooter's angle towards
this.shooter.rotation = this.game.physics.arcade.angleToPointer(this.shooter, this.game.input.activePointer);
//only respond to keys if the player is alive
if (this.player.alive) {
this.player.body.velocity.x = 0;
if (this.game.input.activePointer.isDown) {
console.log("pointer is down");
this.fire();
}
else if (cursors.right.isDown) {
this.playerForward();
}
else if (cursors.left.isDown) {
this.playerBack();
}
else if (cursors.up.isDown) {
this.playerJump();
}
else if (cursors.down.isDown) {
this.fire();
this.playerDuck();
}
}
},
fire: function () {
//for debugging
console.log("fire was called");
console.log(this.game.input.activePointer.x);
console.log(this.game.input.activePointer.y);
if (this.game.time.now > nextFire && playerBullets.countDead() > 0)
{
nextFire = this.game.time.now + fireRate;
var bullet = playerBullets.getFirstExists(false);
bullet.reset(this.shooter.x, this.shooter.y);
currentLoc = this.game.input.activePointer;
bullet.rotation = this.game.physics.arcade.moveToPointer(bullet, 1000, currentLoc, 1000);
console.log(this.game.input.activePointer);
}
},
playerForward: function () {
this.player.loadTexture('player');
this.player.body.setSize(this.player.standDimensions.width, this.player.standDimensions.height);
this.player.body.velocity.x = 700;
this.player.isMoving = true;
//console.log("Forward height:" + this.player.standDimensions.height);
//console.log("Forward width:" + this.player.standDimensions.width);
},
playerBack: function () {
this.player.loadTexture('playerBack');
this.player.body.velocity.x -= 700;
this.player.isMoving = true;
},
playerJump: function () {
if (this.player.body.blocked.down) {
this.player.body.velocity.y -= 700;
this.player.loadTexture('playerJump');
//console.log("Jump height:" + this.player.jumpDimensions.height);
//console.log("Jump width:" + this.player.jumpDimensions.width);
}
},
playerDuck: function () {
//change image and update the body size for the physics engine
this.player.loadTexture('playerDuck');
this.player.body.setSize(this.player.duckedDimensions.width, this.player.duckedDimensions.height);
//keep track of whether player is ducked or not
this.player.isDucked = true;
},
playerDead: function () {
//set to dead (this doesn't affect rendering)
this.player.alive = false;
//stop moving to the right
this.player.body.velocity.x = 0;
//change sprite image
this.player.loadTexture('playerDead');
},
};
Shooter is a blank sprite on top of the player (much like the turret in the tank example) to allow for rotation without the player rotating (please let me know also if there's a better way to do that!).
I tried updating the currentLoc variable in the update method to the activePointer location but that didn't work.
In addition, this condition has never been hit:
if (this.game.input.activePointer.isDown) {
console.log("pointer is down");
this.fire();
}
So something must be going awry with detecting mouse clicks and I don't know if that's part of the problem?
I think you should look it up in the API. There are few points in your code that are questionable.
http://phaser.io/docs/2.3.0/Phaser.Pointer.html
http://phaser.io/docs/2.3.0/Phaser.Physics.Arcade.html#moveToPointer
The point is that you are actually giving the reference to the pointer (to currentLoc) but not the position. So it should always fire to 0;0.
And for the isDown detection, have you done it in the update function or somewhere else?
Hope i could help!