Drawing with sugar - javascript

I want to create a drawing in sugar thing, much the same as you would throw some sugar on a table and using your fingers to "erase" the sugar particles to form an image.
Does anyone know of a js type tool I can use to make this happen?
I suppose I can take a photo of a desk, and a photo of desk with some sugar on it, and then just erase the top layer, but I'm worried that this won't give a real effect.
I'm currently thinking of having a photo of desk, and then using JS to generate a lot of "sugary" particles, which I can then erase. This sounds incredibly hard to do though. Is it? Can someone point me in a good direction?

Sand or is it sugar?
An interesting problem that I had to give a little time.
This works by creating several buffers to hold grains of sand (sugar) and give them life when they need to move.
There is no way that Javascript could do a whole screen of a million plus grains so this demo cheats by only updating a very few and prioritising for new movement rather than allow older moving grains to hog CPU time.
The arrays active, sandStatus, holds the sand gains. active has the pixel address as a 32Bit int and sandStatus has age. The Array sand holds the amount of sand at each pixel and is used to calculate the shadow effect (shadow could be much better using a webGL shader) and to work out which direction sand should slide if disturbed or dropped to the surface.
the var activeMax holds the max number of active sand grains. Increase for a better effect, decrease if the sim runs to slow.
To drop sand use the right mouse button. Hold at one spot to make a pile. Left button pushes the sand about. When you hit a bigger pile the machine may lag (depending on CPU power and browser (best in firefox)).
The push function checks the sand array for any sand. If found it pushes the sand away from the center and piles it up around the edge. Some sand will fall back.
The function sprinkle adds grains of sand (one are a time by pixel coordinate or by index). The function push does the sand drawing FX. update moves the sand grains by checking surrounding pixels heights and moving grains down hill. renderPix handles rendering grains, creating the shadows and deactivating sand grains. The Array shadowChange holds the index of pixels that have had changes so that the shadows can be updated.
Bottom half of the demo is just boilerplate for mouse and canvas setup. All the code in regard to the answer is in the first half.
"use strict";
var activeMax = 2280; // this is the number of sand grains that are processed at
// at time. Increase for better looking effect. decrease
// if the machine is not keeping up with the load
var cw;
var ch;
var w; //
var h;
var canvasBuf = document.createElement("canvas");
var ctxB
var globalTime; // global to this
var pixels
var sand;
var sandToFall;
var sandToFallCount = 36000;
var shadow; // shadow pixels
var activeMax = 2280;
var active; // index of pixel for active grain
var sandStatus; // status of active grain
var shadowChange; // holds index of pixels that have a shadow change
var pixels;
var buf;
var grain = 0xFFFFFFFF;
var shadowGrain = 0x00000000;
var ready = false;
var sandReady = 0;
var nextActive = 0;
var nextActiveShadow = 0;
var onResize = function(){
cw = canvas.width;
ch = canvas.height;
w = cw; //
h = ch;
pixels = w*h;
canvasBuf.width = w;
canvasBuf.height = h;
ctxB = canvasBuf.getContext("2d");
sand = new Uint8ClampedArray(pixels);
shadow = new Uint8ClampedArray(pixels); // shadow pixels
sandToFall = new Uint32Array(sandToFallCount);
activeMax = 2280;
active = new Uint32Array(activeMax); // index of pixel for active grain
sandStatus = new Uint16Array(activeMax); // status of active grain
shadowChange= new Uint32Array(activeMax); // holds index of pixels that have a shadow change
sandStatus.fill(0); // clear
active.fill(0);
shadowChange.fill(0);
ctxB.clearRect(0,0,w,h);
ctxB.fillStyle = "white";
ctxB.font = "84px arial";
ctxB.textAlign = "center";
ctxB.globalAlpha = 0.01;
for(var i = 0; i < 12; i ++){
ctxB.fillText("Sand Doodler!",w/2 + (Math.random()-0.5)*5,h/2 + (Math.random()-0.5)*5);
}
ctxB.globalAlpha = 1;
pixels = ctxB.getImageData(0,0,w,h);
buf = new Uint32Array(pixels.data.buffer);
for(i = 0; i < buf.length; i += 3){
if(buf[i] !== 0){
var c = buf[i] >>> 24;
buf[i] = 0;
while(c > 0){
var ind = Math.floor(Math.random()*sandToFallCount);
if(sandToFall[ind] === 0){
sandToFall[ind] = i;
}
c = c >>> 1;
}
}
}
buf.fill(0);
offsets = [1,w-1,w,w+1,-w-1,-w,-w+1,-1];
shadowOffsets = [-w-1,-w,-1];
ready = true;
sandReady=0;
}
function sprinkle(x,y){
var ind;
if(y === undefined){
ind = x;
}else{
ind = x + y*w;
}
var alreadyExists = active.indexOf(ind);
var ac = nextActive;
if(alreadyExists > -1){
sand[ind] += 1;
shadow[ind] = 0;
sandStatus[alreadyExists] = 66;
}else{
active[nextActive] = ind;
sandStatus[nextActive] = 66;
shadowChange[nextActiveShadow];
nextActiveShadow = (nextActiveShadow+1)%activeMax;
nextActive = (nextActive +1)%activeMax;
sand[ind] += 1;
shadow[ind] = 0;
}
return ac;
}
var offsets = [1,w-1,w,w+1,-w-1,-w,-w+1,-1];
var offsetCount = 8;
function update(){
var min,max,minDir,maxDir,dir,start,jj,j,ind,level,i,l1;
for( i = 0; i <activeMax; i ++){
if(sandStatus[i] !== 0){
ind = active[i];
level = sand[ind];
if(level === 1){
sandStatus[i] = 1; // deactive is cant move (level ground)
}else{
min = level;
var d;
minDir = offsets[Math.floor(Math.random()*16)];
dir = null;
start = Math.floor(Math.random()*16); // start at a random direction
for(j=0;j < offsetCount; j++){
jj = offsets[(j + start)%offsetCount];
l1 = sand[ind+jj];
if(l1 < min){
min = l1;
minDir = jj;
d = (j + start)%offsetCount;
}
}
dir = null;
if(min >= level - 1){ // nowhere to move
sandStatus[i] = 1;
}else
if(min < level-1){ // move to lowest
dir = minDir
}
if(dir !== null){
var lv = level-min;
while(lv > 2){
active[i] = ind + dir;
if(sand[ind] > 1){
sand[ind] -= 2;
sprinkle(ind)
}else{
sand[ind] -=1;
}
ind = ind+dir;
sand[active[i]] += 1;
if(sand[active[i] + offsets[d]] >=level){
d+= Math.random()<0.5? 1 : offsetCount -1;
d %=offsetCount;
}
lv -= 1;
}
if(sand[ind]>0){
active[i] = ind + dir;
sand[ind] -= 1;
}
sand[active[i]] += 1;
}
}
}
}
}
var shadowOffsets = [-w-1,-w,-1];
var shadowCols = [0xFFf0f0f0,0xFFd0d0d0,0xFFb0b0b0,0xFF909090];
var shadowDist = [0xf0000000,0xd0000000,0xb0000000,0x90000000]; // shadow col no sand
// renders grains and adds shadows. Deactivates gains when they are done
function renderPix(){
var ac = 0;
for(var i = 0; i < activeMax; i ++){
if(sandStatus[i] !== 0){
ac += 1;
var ind = active[i];
buf[ind] = grain;
}
}
for(var i = 0; i < activeMax; i ++){
if(sandStatus[i] !== 0){
var ind = active[i];
var level = sand[ind];
var col =0;
if(sand[ind + shadowOffsets[0]] > level ){
col = 2;
}else
if(sand[ind + shadowOffsets[1]] > level ){
col =1;
}else
if(sand[ind + shadowOffsets[2]] > level ){
col = 1;
}
buf[ind] = grain; // add a sand grain to the image
shadow[ind] = col;
shadowChange[nextActiveShadow] = ind;
nextActiveShadow = (nextActiveShadow + 1)%activeMax;
var c = 4;
while(c > 0){
c-=1;
ind += w + 1;
var s = sand[ind];
var dif = level - s;
if(dif > 0){
c-= dif;
}
shadow[ind] += 1;
shadowChange[nextActiveShadow] = ind;
nextActiveShadow = (nextActiveShadow + 1)%activeMax;
}
sandStatus[i] -= 1;
if(sandStatus[i] === 1){
sandStatus[i] = 0;
active[i] = 0;
}
}
}
// add calculated shadows
for(var i = 0; i < activeMax; i ++){
if(shadowChange[i] !== 0){
var ind = shadowChange[i];
var s = shadow[ind] <4 ? shadow[ind]-1:3;
if(sand[ind] > 0){
buf[ind]=shadowCols[s];
}else{
buf[ind]=shadowDist[s];
}
shadowChange[i] = 0;
}
}
}
// push sand about
function push(x,y,radius){
var iyy,iny
var rr = radius * radius ;
x = Math.floor(x);
y = Math.floor(y);
for(var iy = -radius + 1; iy < radius; iy ++){
iyy = iy * iy;
iny = (y+iy) * w;
for(var ix = -radius + 1; ix < radius; ix ++){
if(ix*ix + iyy <= rr){ // is inside radius
var ind = (x + ix) + iny;
if(sand[ind] > 0){
var dir = Math.random() * Math.PI * 2;
dir = Math.atan2(iy,ix)
var r = radius + Math.random() * radius *0.2
var xx = Math.cos(dir) * r;
var yy = Math.sin(dir) * r;
buf[ind] = 0x000000;
sand[ind] = 0;
ind = Math.floor(xx + x) + Math.floor(yy + y) * w;
sprinkle(ind);
}else{
buf[ind] = 0;
}
}
}
}
}
function showHeight(){ // for debugging only
for(var i = 0; i < sand.length; i ++){
buf[i] = 0xff000000;
var k = sand[i];
buf[i] +=(k <<16) + (k<<8) + (k);
}
}
// main update function
function display(){
if(!ready){ // only when ready
return;
}
//ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.clearRect(0,0,cw,ch);
var mx = Math.floor((mouse.x/cw)*w); // canvas buf mouse pos
var my = Math.floor((mouse.y/ch)*h);
// drop sand
if(mouse.buttonRaw & 4){
for(var i = 0; i < 120; i ++){
var dir = Math.random()*Math.PI;
var dist = ((Math.random()+Math.random()+Math.random())/3-0.5) * 62;
var x = Math.cos(dir) * dist;
var y = Math.sin(dir) * dist;
x += mx;
y += my;
x = Math.floor(x); // floor
y = Math.floor(y); // floor
sprinkle(x,y);
}
}else{
// drop sand for intro FX
if(sandReady <sandToFallCount){
for(var i = 0; i < 120; i ++){
if(sandToFall[sandReady] !== 0){
sprinkle(sandToFall[sandReady] + offsets[Math.floor(Math.random()*8)%offsets.length]);
}
sandReady += 1;
}
}
}
// push sand about.
if(mouse.buttonRaw & 1){
push(((mouse.x/cw)*w),((mouse.y/ch)*h),32); // scale mouse to canvasBuf size
}
update();
renderPix();
//showHeight();
ctxB.putImageData(pixels,0,0);
ctx.drawImage(canvasBuf,0,0,cw,ch);
}
//==================================================================================================
// The following code is support code that provides me with a standard interface to various forums.
// It provides a mouse interface, a full screen canvas, and some global often used variable
// like canvas, ctx, mouse, w, h (width and height), globalTime
// This code is not intended to be part of the answer unless specified and has been formated to reduce
// display size. It should not be used as an example of how to write a canvas interface.
// By Blindman67
const U = undefined;const RESIZE_DEBOUNCE_TIME = 100;
var canvas,ctx,mouse,createCanvas,resizeCanvas,setGlobals,globalTime=0,resizeCount = 0;
createCanvas = function () { var c,cs; cs = (c = document.createElement("canvas")).style; cs.position = "absolute"; cs.top = cs.left = "0px"; cs.zIndex = 1000; document.body.appendChild(c); return c;}
resizeCanvas = function () {
if (canvas === U) { canvas = createCanvas(); } canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") { setGlobals(); } if (typeof onResize === "function"){ resizeCount += 1; setTimeout(debounceResize,RESIZE_DEBOUNCE_TIME);}
}
function debounceResize(){ resizeCount -= 1; if(resizeCount <= 0){ onResize();}}
setGlobals = function(){ cw = w = canvas.width; ch = h = canvas.height; mouse.updateBounds(); }
mouse = (function(){
function preventDefault(e) { e.preventDefault(); }
var mouse = {
x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false, buttonRaw : 0, over : false, bm : [1, 2, 4, 6, 5, 3],
active : false,bounds : null, crashRecover : null, mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
var m = mouse;
function mouseMove(e) {
var t = e.type;
m.x = e.clientX - m.bounds.left; m.y = e.clientY - m.bounds.top;
m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1]; }
else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2]; }
else if (t === "mouseout") { m.buttonRaw = 0; m.over = false; }
else if (t === "mouseover") { m.over = true; }
else if (t === "mousewheel") { m.w = e.wheelDelta; }
else if (t === "DOMMouseScroll") { m.w = -e.detail; }
if (m.callbacks) { m.callbacks.forEach(c => c(e)); }
if((m.buttonRaw & 2) && m.crashRecover !== null){ if(typeof m.crashRecover === "function"){ setTimeout(m.crashRecover,0);}}
e.preventDefault();
}
m.updateBounds = function(){
if(m.active){
m.bounds = m.element.getBoundingClientRect();
}
}
m.addCallback = function (callback) {
if (typeof callback === "function") {
if (m.callbacks === U) { m.callbacks = [callback]; }
else { m.callbacks.push(callback); }
} else { throw new TypeError("mouse.addCallback argument must be a function"); }
}
m.start = function (element, blockContextMenu) {
if (m.element !== U) { m.removeMouse(); }
m.element = element === U ? document : element;
m.blockContextMenu = blockContextMenu === U ? false : blockContextMenu;
m.mouseEvents.forEach( n => { m.element.addEventListener(n, mouseMove); } );
if (m.blockContextMenu === true) { m.element.addEventListener("contextmenu", preventDefault, false); }
m.active = true;
m.updateBounds();
}
m.remove = function () {
if (m.element !== U) {
m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); } );
if (m.contextMenuBlocked === true) { m.element.removeEventListener("contextmenu", preventDefault);}
m.element = m.callbacks = m.contextMenuBlocked = U;
m.active = false;
}
}
return mouse;
})();
function main(timer){ // Main update loop
globalTime = timer;
display(); // call demo code
requestAnimationFrame(main);
}
resizeCanvas();
mouse.start(canvas,true);
window.addEventListener("resize",resizeCanvas);
requestAnimationFrame(main);
body {
background:#49D;
}
.help {
text-align : center;
font-family : Arial,"Helvetica Neue",Helvetica,sans-serif;
font-size : 18px;
}
<div class="help">Right mouse to drop sand, left button to push it around.</div>

Related

I am having an issue redrawing some circles onto my html canvas

I am using a basic html canvas to create a simple game using javascript, but I am having an issue while trying to redraw my window. I have created a redraw_window function that I call whenever i want a new frame to show on the screen, but when I try to call the redraw_window function from this location on line 151, it does not work. The screen does not update. Any ideas why?
const c = canvas.getContext("2d")
canvas.width = innerWidth
canvas.height = innerHeight
const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;
class Light {
constructor(pos,vel){
this.pos = pos
this.vel = vel
}
move(){
if (this.pos == 0){
this.vel = 1
}
if(this.pos == 9){
this.vel = -1
}
this.pos += this.vel
}
}
function is_not_in(val,list){
for (var i = 0; i < list.length; i++){
if (list[i] == val){
return false
}
}
return true
}
function clear_window(){
c.clearRect(0,0,canvas.width,canvas.height)
}
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
function redraw_window(pos){
c.font = "80px serif"
//let board = [1,1,1,1,1,1,1,1,1,1]
positions = [canvas.width/2-450,canvas.width/2-350,canvas.width/2-250,canvas.width/2-150,canvas.width/2-50,canvas.width/2+50,canvas.width/2+150,canvas.width/2+250,canvas.width/2+350,canvas.width/2+450,]
//board[light.pos] = 0
clear_window()
c.fillStyle = "black"
//c.fillText(board.toString(),canvas.width/2-c.measureText(board.toString()).width/2,canvas.height/2)
//c.fillText("Troy likes big hairy black balls",canvas.width/2-c.measureText("Troy likes big hairy black balls").width/2,canvas.height/2+80)
for (var i = 0; i < positions.length; i++) {
let radius = 20
if (pos != i){
c.beginPath()
c.arc(positions[i],canvas.height/2,radius,0,Math.PI * 2,false)
c.fillStyle = "black"
c.fill()
}
if (pos == i){
c.beginPath()
c.arc(positions[i],canvas.height/2,radius,0,Math.PI * 2,false)
c.fillStyle = "green"
c.fill()
}
}
}
function choose(choices) {
var index = Math.floor(Math.random() * choices.length);
return choices[index];
}
function win_animation(){
redraw_window(null)
sleep(300)
redraw_window(light.pos)
sleep(300)
redraw_window(null)
sleep(300)
redraw_window(light.pos)
}
var light = new Light(random(0,9),choose([-1,1]))
function main(){
var FPS = 60
var SPEED = 0.5
var COOLDOWN = FPS * 0.25
var SCORE_TO_WIN = 5
var right_player_points = 0
var left_player_points = 0
var frame = 0
var right_player_cooldown = 0
var left_player_cooldown = 0
var keys_pressed = []
var right_player_key = "ShiftRight"
var left_player_key = "ShiftLeft"
var right_player_cooldown = 0
var left_player_cooldown = 0
var playing = true
//handles cooldown and keys pressed list
window.addEventListener("keydown",(event)=>{
if (event.code == right_player_key && is_not_in(right_player_key,keys_pressed)){
if (right_player_cooldown == 0){
right_player_cooldown = COOLDOWN
keys_pressed.push(event.code)
}
}
if (event.code == left_player_key && is_not_in(left_player_key,keys_pressed)){
if (left_player_cooldown == 0){
left_player_cooldown = COOLDOWN
keys_pressed.push(event.code)
}
}
})
//runs fps times per second
var run = setInterval(run,1000 / FPS)
function run(){
frame += 1
if (left_player_cooldown > 0){
left_player_cooldown -= 1
}
if (right_player_cooldown > 0){
right_player_cooldown -= 1
}
//runs SPEED times per second
if (frame >= FPS * SPEED){
frame = 0
if (!is_not_in(right_player_key,keys_pressed) && light.pos == 9){
right_player_points += 1
**VVV THIS IS WHERE I AM HAVING MY ISSUE VVV**
redraw_window(null);
alert("right player:" + right_player_points.toString())
if (right_player_points >= SCORE_TO_WIN){
alert("right player Wins")
right_player_points = 0
left_player_points = 0
light = new Light(random(0,9),choose([-1,1]))
}
}
if (!is_not_in(left_player_key,keys_pressed) && light.pos == 0){
left_player_points += 1
light = new Light(random(0,9),choose([-1,1]))
alert("left player:" + left_player_points.toString())
if (left_player_points >= SCORE_TO_WIN){
alert("left player wins")
left_player_points = 0
right_player_points = 0
}
}
light.move()
redraw_window(light.pos)
keys_pressed = []
}
}
}
main() ```
The main issue I can see here is that you have a variable and a function both named run. The setInterval call is being overwritten with the function definition. I recommend you rename the variable run to runInterval.
Change
var run = setInterval(run, 1000 / FPS)
to
var runInterval = setInterval(run, 1000 / FPS)
See if that helps.

How to center scaling of game world in Create.js?

I am creating a Create.js 2D game engine in JavaScript and need a way to center the player (which will be a sprite placed in the center of the screen) when the main container is scaled. It should be an offset to the containers translation every time the world is scaled, but I can't figure out how to do the calculation so I have put a ?? and comments where I need help with the code. How do I figure out how much to translate the container to the center when it is scaled? Code below.
var stage;
var canvas;
var map;
var move = [];
var viewDist = 2;
var chunkSize = 16;
var mapSize = 32;
var view_chunks = [];
var chunks = [];
var posX;
var posY;
var tileSize = 16;
var chunksContainer;
var playerPosX = 0;
var playerPosY = 0;
var chunkPosX = 0;
var chunkPosY = 0;
var scale = 3;
var SPRITESHEET;
var tiles = [];
var speed = 0.2;
var moveForward = false;
var moveBackward = false;
var chunksContainer = new createjs.Container();
var halfW = window.innerWidth/2
var halfH = window.innerHeight/2
var scaleFactor = 0.1;
this.document.onkeydown = keydown;
function keydown(event) {
/** you can access keyCode to determine which key was pressed**/
var keyCode = event.keyCode;
if(keyCode == 87){
move[0] = true;
}
if(keyCode == 83){
move[1] = true;
}
if(keyCode == 65){
move[2] = true;
}
if(keyCode == 68){
move[3] = true;
}
if(keyCode == 187){
if(scale < 4){
scale = scale + 0.1;
}
}
if(keyCode == 189){
if(scale > ((viewDist*2+5)*chunkSize*tileSize)/window.innerWidth){
scale = scale - 0.1;
//chunksContainer.x = chunksContainer.x ??
//chunksContainer.y = chunksContainer.y ??
}
console.log(scale)
}
//console.log(keyCode)
}
this.document.onkeyup = keyup;
function keyup(event) {
/** you can access keyCode to determine which key was pressed**/
var keyCode = event.keyCode;
if(keyCode == 87){
move[0] = false;
}
if(keyCode == 83){
move[1] = false;
}
if(keyCode == 65){
move[2] = false;
}
if(keyCode == 68){
move[3] = false;
}
console.log(event.keyCode)
}
function generateMap() {
map = [];
for(var x = 0; x < mapSize*chunkSize; x++){
map[x] = []
for(var y = 0; y < mapSize*chunkSize; y++){
map[x][y] = 5;
if(Math.floor(Math.random() * 11) == 1){
map[x][y] = 1;
}
}
}
}
function getTile(col,row,x,y){
col = col%mapSize;
row = row%mapSize;
if(col < 0){
col = mapSize + col;
}
if(row < 0){
row = mapSize + row;
}
col = Math.abs(col);
row = Math.abs(row);
return map[col*chunkSize + x][row*chunkSize+y]
}
function init(){
canvas = document.getElementById("canvas");
canvas.width = document.body.clientWidth; //document.width is obsolete
canvas.height = document.body.clientHeight; //document.height is obsolete
// create a new stage and point it at our canvas:
stage = new createjs.Stage("canvas");
// load the spritesheet image:
var image = new Image();
image.onload = handleLoad;
image.src = "../assets/spritesheet/roguelikeSheet_transparent.png";
}
var tiles;
function generateChunks(x,y){
chunksContainer = new createjs.Container();
chunksContainer.scale = scale;
chunksContainer.x = 0
chunksContainer.y = 0
chunksContainer.regX = (viewDist*2)*chunkSize*tileSize/2
chunksContainer.regY = (viewDist*2)*chunkSize*tileSize/2
for(col = 0; col < viewDist*2; col++){
tiles[col] = []
for(row = 0; row < viewDist*2; row++){
tiles[col][row] = []
for (var x=0; x<chunkSize; x++) {
tiles[col][row][x] = []
for (var y=0; y<chunkSize; y++) {
var idx = getTile(chunkPosX + col,chunkPosY + row,x,y);
tiles[col][row][x][y] = new createjs.Sprite(SPRITESHEET)
.set({x: 16*(col * 16 + x), y:16*(row * 16 + y)});
tiles[col][row][x][y].gotoAndStop(idx);
chunksContainer.addChild(tiles[col][row][x][y]);
}
}
}
}
stage.addChild(chunksContainer);
}
function updateChunks(){
for(col = 0; col < viewDist*2; col++){
for(row = 0; row < viewDist*2; row++){
for (var x=0; x<chunkSize; x++) {
for (var y=0; y<chunkSize; y++) {
var idx = getTile(chunkPosX + col,chunkPosY + row,x,y);
tiles[col][row][x][y].gotoAndStop(idx);
}
}
}
}
}
function handleLoad(evt) {
// define the spritesheet:
SPRITESHEET = new createjs.SpriteSheet({
images: [evt.target],
frames: {width:16, height:16, regX:16, regY:16, spacing:1, margin:0, count:1680}
});
generateMap();
generateChunks();
stage.update();
// update the stage to draw to screen:
createjs.Ticker.addEventListener("tick", handleTick);
}
chunkPlayerPosY = 0;
chunkPlayerPosX = 0;
function handleTick(event) {
if(move[0]){
chunksContainer.y = chunksContainer.y + speed * createjs.Ticker.getMeasuredTickTime() * scale;
}
if(move[1]){
chunksContainer.y = chunksContainer.y - speed * createjs.Ticker.getMeasuredTickTime() * scale;
}
if(move[2]){
chunksContainer.x = chunksContainer.x + speed * createjs.Ticker.getMeasuredTickTime() * scale;
}
if(move[3]){
chunksContainer.x = chunksContainer.x - speed * createjs.Ticker.getMeasuredTickTime() * scale;
}
if(chunksContainer.y > halfH + chunkSize*tileSize * scale){
chunksContainer.y = halfH;
chunkPosY = chunkPosY - 1
console.log(chunkPosY)
updateChunks();
}
if(chunksContainer.y < halfH){
chunksContainer.y = halfH + chunkSize*tileSize * scale;
chunkPosY = chunkPosY + 1
console.log(chunkPosY)
updateChunks();
}
if(chunksContainer.x > halfW + chunkSize*tileSize * scale){
chunksContainer.x = halfW;
chunkPosX = chunkPosX - 1
console.log(chunkPosX)
updateChunks();
}
if(chunksContainer.x < halfW){
chunksContainer.x = halfW + chunkSize * tileSize * scale;
chunkPosX = chunkPosX + 1
console.log(chunkPosX)
updateChunks();
}
chunksContainer.scale = scale;
stage.update();
}

Make movement more smooth on Java Script Game | JavaScript Canvas

I am working on very simple java script game. there's a falling random object (trash) and another object for catch the falling object (trash bin). everything seems fine but i wanted to make the movement of the trash bin more smooth. Do you have any idea to fix this? Thanks in Advance
this is my code
window.onload = function(){
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var canvasBack = document.getElementById("backgroundCanvas");
var contextBack = canvasBack.getContext("2d");
var timer;
//mengatur hiscore
var hiscore = 0;
//Background image, musik and arrays musik.
var background = new Image();
background.src = 'assets/bgw2.jpg';
var catchSounds = [];
var catchSoundCounter = 0;
for(var i = 0; i < 5; i++)
{
var catchSound = new Audio();
catchSound.src = 'Audio/bleep.wav';
catchSounds.push(catchSound);
}
var music = new Audio();
music.src = 'Audio/MarimbaBoy.wav';
music.loop = true;
var smashSounds = [];
var smashCounter = 0;
for(var i = 0; i < 5; i++)
{
var smash = new Audio();
smash.src = 'Audio/smash.mp3';
smashSounds.push(smash);
}
var player;
var fruits = [];
var numberOfFruits = 15;
//Player constructor
function Player()
{
this.gameOver = false;
this.score = 0;
this.fruitsCollected = 0;
this.fruitsMissed = 0;
this.playerWidth = 150;
this.playerHeight = 90;
this.playerSpeed = 10;
this.x = canvas.width / 2;
this.y = canvas.height - this.playerHeight;
this.playerImage = new Image();
this.playerImage.src = 'assets/binn.png';
//Draws the player
this.render = function()
{
context.drawImage(this.playerImage, this.x, this.y);
}
//Moves the player left
this.moveLeft = function()
{
if(this.x > 0)
{
this.x -= this.playerSpeed;
}
}
//Moves the player right
this.moveRight = function()
{
if(this.x < canvas.width - this.playerWidth)
{
this.x += this.playerSpeed;
}
}
}
//Fruit constructor
function Fruit()
{
this.fruitNumber = Math.floor(Math.random() * 5);
this.fruitType = "";
this.fruitScore = 0;
this.fruitWidth = 50;
this.fruitHeight = 50;
this.fruitImage = new Image();
this.fruitSpeed = Math.floor(Math.random() * 2 + 1);
this.x = Math.random() * (canvas.width - this.fruitWidth);
this.y = Math.random() * -canvas.height - this.fruitHeight;
//Creates a different kind of fruit depending on the fruit number
//which is generated randomly
this.chooseFruit = function()
{
if(this.fruitNumber == 0)
{
this.fruitType = "pisang";
this.fruitScore = 5 * this.fruitSpeed;
this.fruitImage.src = 'assets/pisang.png';
}
else if(this.fruitNumber == 1)
{
this.fruitType = "rubbish";
this.fruitScore = 10 * this.fruitSpeed;
this.fruitImage.src = 'assets/rubbish.png';
}
else if(this.fruitNumber == 2)
{
this.fruitType = "botol";
this.fruitScore = 15 * this.fruitSpeed;
this.fruitImage.src = 'assets/botol.png';
}
else if(this.fruitNumber == 3)
{
this.fruitType = "coke";
this.fruitScore = 20 * this.fruitSpeed;
this.fruitImage.src = 'assets/coke.png';
}
else if(this.fruitNumber == 4)
{
this.fruitType = "apple";
this.fruitScore = 25 * this.fruitSpeed;
this.fruitImage.src = 'assets/apple.png';
}
else if(this.fruitNumber == 5)
{
this.fruitType = "papikra";
this.fruitScore = 30 * this.fruitSpeed;
this.fruitImage.src = 'assets/papikra.png';
}
}
//Makes the fruit descend.
//While falling checks if the fruit has been caught by the player
//Or if it hit the floor.
this.fall = function()
{
if(this.y < canvas.height - this.fruitHeight)
{
this.y += this.fruitSpeed;
}
else
{
smashSounds[smashCounter].play();
if(smashCounter == 4)
{
smashCounter = 0;
}
else
{
smashCounter++;
}
player.fruitsMissed += 1;
this.changeState();
this.chooseFruit();
}
this.checkIfCaught();
}
//Checks if the fruit has been caught by the player
//If it is caught, the player score and fruit counter is increased, and
//the current fruit changes its state and becomes a different fruit.
this.checkIfCaught = function()
{
if(this.y >= player.y)
{
if((this.x > player.x && this.x < (player.x + player.playerWidth)) ||
(this.x + this.fruitWidth > player.x && this.x + this.fruitWidth < (player.x + player.playerWidth)))
{
catchSounds[catchSoundCounter].play();
if(catchSoundCounter == 4)
{
catchSoundCounter = 0;
}
else
{
catchSoundCounter++;
}
player.score += this.fruitScore;
player.fruitsCollected += 1;
this.changeState();
this.chooseFruit();
}
}
}
//Randomly updates the fruit speed, fruit number, which defines the type of fruit
//And also changes its x and y position on the canvas.
this.changeState = function()
{
this.fruitNumber = Math.floor(Math.random() * 5);
this.fruitSpeed = Math.floor(Math.random() * 2 + 1);
this.x = Math.random() * (canvas.width - this.fruitWidth);
this.y = Math.random() * -canvas.height - this.fruitHeight;
}
//Draws the fruit.
this.render = function()
{
context.drawImage(this.fruitImage, this.x, this.y);
}
}
//Adds controls. Left arrow to move left, right arrow to move right.
//ENTER to restart only works at the game over screen.
window.addEventListener("keydown", function(e){
e.preventDefault();
if(e.keyCode == 37)
{
player.moveLeft();
}
else if(e.keyCode == 39)
{
player.moveRight();
}
else if(e.keyCode == 13 && player.gameOver == true)
{
main();
window.clearTimeout(timer);
}
});
main();
//Fills an array of fruits, creates a player and starts the game
function main()
{
contextBack.font = "bold 20px Dominique";
contextBack.fillStyle = "WHITE";
player = new Player();
fruits = [];
for(var i = 0; i < numberOfFruits; i++)
{
var fruit = new Fruit();
fruit.chooseFruit();
fruits.push(fruit);
}
startGame();
}
function startGame()
{
updateGame();
window.requestAnimationFrame(drawGame);
}
//Checks for gameOver and makes each fruit in the array fall down.
function updateGame()
{
music.play();
if(player.fruitsMissed >= 10)
{
player.gameOver = true;
}
for(var j = 0; j < fruits.length; j++)
{
fruits[j].fall();
}
timer = window.setTimeout(updateGame, 30);
}
//Draws the player and fruits on the screen as well as info in the HUD.
function drawGame()
{
if(player.gameOver == false)
{
context.clearRect(0, 0, canvas.width, canvas.height);
contextBack.clearRect(0, 0, canvasBack.width, canvasBack.height);
contextBack.drawImage(background, 0, 0);
player.render();
for(var j = 0; j < fruits.length; j++)
{
fruits[j].render();
}
contextBack.fillText("SCORE: " + player.score, 30, 50);
contextBack.fillText("HIGHEST SCORE: " + hiscore, 140, 50);
contextBack.fillText("FRUIT CAUGHT: " + player.fruitsCollected, 320, 50);
contextBack.fillText("FRUIT MISSED: " + player.fruitsMissed, 490, 50);
}
else
{
//Different screen for game over.
for(var i = 0; i < numberOfFruits; i++)
{
console.log("Speed was" + fruits[fruits.length - 1].fruitSpeed);
fruits.pop();
}
if(hiscore < player.score)
{
hiscore = player.score;
contextBack.fillText("NEW HI SCORE: " + hiscore, (canvas.width / 2) - 80, canvas.height / 2);
}
contextBack.fillText("PRESS ENTER TO RESTART", (canvas.width / 2) - 100, canvas.height / 2 + 50);
context.clearRect(0, 0, canvas.width, canvas.height);
}
window.requestAnimationFrame(drawGame);
}
}
First of all, just use one requestAnimationFrame and no other setTimeout code. These can start to run out of sync with each other and it's hard to pause them all when the player wants to pause the game.
Instead, use a counter instead of timeout.
let fruitCounter = 0
function drawGame() {
// all your draw code here
...
// every 60 frames drop a new fruit
fruitCounter++
if(fruitCounter > 60){
fruitCounter = 0
dropNewFruit()
}
// request the new frame unless its game over
if(!gameOver) {
requestAnimationFrame(drawGame)
}
}
Also, if you use keyboard events like this, it will always be choppy because there is a delay when typing on the keyboard (just press a letter for a long time in a text field, you will see that it takes a while until more letters appear)
You can fix this by setting a variable once a key gets pressed.
window.addEventListener("keydown", function(e){
if(e.keyCode == 37){
moveLeft = 1
}
}
window.addEventListener("keyup", function(e){
if(e.keyCode == 37){
moveLeft = 0
}
}
Then, you can use that variable in your animation code
function drawGame() {
// all your draw code here
player.x += moveLeft
// request the new frame unless its game over
if(!gameOver) {
requestAnimationFrame(drawGame)
}
}
These are just a few tips! This has always worked for me when I build a javascript game.

Control ball speed in pong

I have this code below, and I'm having a hard time solving this one.
On dotime function, i have the ball speed:
/* HERE */
function dotime() {
move1();
if (myform != null) {
myform.text3.value = display1();
myform.score.value = "" + score;
}
/* ---Ball Speed--- */
if (!oops_flag) timerID = setTimeout("dotime()", 190);
/* ---trying to make ball speed faster--- */
if (score == 1) {
timerID = setTimeout("dotime()", 100 - 30);
}
timerRunning = true;
}
I tried to make the ball move faster but when i do the second "if", the ball just flying too fast.
Thanks in advance,
fufle.
full code:
var crlf = "\r\n";
var x = 0;
var y = 0;
var dx = 1;
var dy = 1;
var s = "";
var u = 0;
var oops_flag = false;
var score = 0;
function move1() {
x += dx;
if (x > 61) {
x -= 2 * Math.abs(dx);
if (dx > 0) dx = -dx;
}
if (x < 0) {
x += 2 * Math.abs(dx);
if (dx < 0) dx = -dx;
}
y += dy;
if (y > 24) {
y -= 2 * Math.abs(dy);
if (dy > 0) dy = -dy;
if (Math.abs(x - 2 * u - 1) > 2) {
oops_flag = true;
} else {
score += 1;
}
}
if (y < 0) {
y += 2 * Math.abs(dy);
if (dy < 0) dy = -dy;
}
}
function display1() {
var s1 = ""
var i, j;
if (oops_flag) return " Unlucky, Play again?"
for (j = 0; j < 25; j++) {
for (i = 0; i < 62; i++) {
/* BALL */
if (j == y && i == x) s1 += "🔴";
else s1 += " ";
}
s1 += crlf;
}
/* DEFENDER */
var s2 = "";
for (i = 0; i < 31; i++) {
if (u == i) s2 += "â–„â–„â–„â–„â–„";
else s2 += " ";
}
return (s1 + s2);
}
var timerID = null;
var timerRunning = false;
var myform;
function stopclock() {
if (timerRunning) clearTimeout(timerID);
timerRunning = false;
}
function startclock(form) {
myform = form;
oops_flag = false;
score = 0;
if (navigator.userAgent.indexOf("Mac") > 2) crlf = "\n";
stopclock();
dotime();
// var id= setInterval(frameElement,10000);
}
/* HERE */
function dotime() {
move1();
if (myform != null) {
myform.text3.value = display1();
myform.score.value = "" + score;
}
if (!oops_flag) timerID = setTimeout("dotime()", 100);
if (score == 1) {
timerID = setTimeout("dotime()", 100 - 30);
}
timerRunning = true;
}
Looks like you have two timers running so you need to make it so only one will run.
if (!oops_flag) {
var speed = 100;
if (score===1) speed = 70;
timerID = setTimeout(dotime, speed);
}
or with a ternary operator
if (!oops_flag) {
var speed = (score===1) ? 70 : 100;
timerID = setTimeout(dotime, speed);
}

canvas layer puzzle and piece

I have a puzzle and piece. Piece 5 x 5 covering all puzzle.
When client on click piece, piece disable, show part puzzle underneath piece. I using canvas draw two layer but not working.
function init( img ){
if( img == undefined ){
img="http://amitysmiletravel.com/sites/a/am/amity/uploads/ckfinder/images/amitysmile-hotel(10).jpg";
}
_img = new Image();
_img.addEventListener('load',onImage,false);
_img.src = img ;
}
function onImage(e){
_pieceWidth = Math.floor(_img.width / PUZZLE_DIFFICULTY)
_pieceHeight = Math.floor(_img.height / PUZZLE_DIFFICULTY)
_puzzleWidth = _pieceWidth * PUZZLE_DIFFICULTY;
_puzzleHeight = _pieceHeight * PUZZLE_DIFFICULTY;
setCanvas();
initPuzzle();
}
function setCanvas(){
_canvas = $('#game-state');
_stage = _canvas[0].getContext('2d');
_canvas[0].width = _puzzleWidth;
_canvas[0].height = _puzzleHeight;
// _canvas[0].style.border = "1px solid #004D3D";
}
function initPuzzle(){
_pieces = [];
_mouse = {x:0,y:0};
_currentPiece = null;
_currentDropPiece = null;
_stage.drawImage(_img, 0, 0, _puzzleWidth, _puzzleHeight, 0, 0, _puzzleWidth, _puzzleHeight);
initPieces();
}
function initPieces(){
/*if( img == undefined ){
img="<?php echo Yii::app()->theme->baseUrl?>/images/piece_bg.png";
}*/
_imgPiece = new Image();
_imgPiece.addEventListener('load',buildPieces,false);
_imgPiece.src = "<?php echo Yii::app()->theme->baseUrl?>/images/piece_bg.png";
}
var buildPieces = function(){
_stage.clearRect(0,0,_puzzleWidth,_puzzleHeight);
var i;
var piece ;
var xPos = 0;
var yPos = 0;
for(i = 0; i < 25; i++){
piece ={};
piece.xPos = xPos;
piece.yPos = yPos;
_pieces.push(piece);
_stage.drawImage(_imgPiece,piece.xPos,piece.yPos,_pieceWidth,_pieceHeight);
_stage.strokeRect(xPos,yPos,_pieceWidth,_pieceHeight);
xPos += _pieceWidth;
if(xPos >= _puzzleWidth){
xPos = 0;
yPos += _pieceHeight;
}
}
if( !touchSupported ){
$('#game-state').on('mousedown', onPuzzleClick);
}else{
// document.ontouchstart = null;
$('#game-state').on('touchstart',function( e ){
var e = e.originalEvent;
e.preventDefault();
onPuzzleClick( e );
});
}
}
function onPuzzleClick(e){
// alert(e);
if( !Modernizr.touch ){
_mouse.x = e.pageX - _canvas.offset().left;
_mouse.y = e.pageY - _canvas.offset().top;
}else{
_mouse.x = e.touches[0].pageX - _canvas.offset().left;
_mouse.y = e.touches[0].pageY - _canvas.offset().top;
}
// alert("x "+_mouse.x+" y: "+_mouse.y);
_currentPiece = checkPieceClicked();
if(_currentPiece != null){
_stage.clearRect(_currentPiece.xPos,_currentPiece.yPos,_pieceWidth,_pieceHeight);
_stage.save();
}
}
function checkPieceClicked(){
var i;
var piece;
for(i = 0;i < _pieces.length;i++){
piece = _pieces[i];
if(_mouse.x < piece.xPos || _mouse.x > (piece.xPos + _pieceWidth) || _mouse.y < piece.yPos || _mouse.y > (piece.yPos + _pieceHeight)){
//PIECE NOT HIT
}
else{
return piece;
}
}
return null;
}
please help me. Thank!

Categories

Resources