I am using Teechart library to display y axes in the time intervals of 1 second. Chart1.axes.left.increment = 1; helps me to increment the yaxis in the interval of 1. What i need is to lay out dotted lines in between these Solid lines. I want to manually add the line series for dotted lines in time interval of 0.20 seconds. How can I use line series to add dotted lines here.
function draw_TeeChart() {
var w = window.innerWidth, h = window.innerHeight;
// Initialize Teechart[![enter image description here][1]][1]
Chart1 = new Tee.Chart("canvas");
document.getElementById("canvas").style.position = "relative";
document.getElementById("canvas").width= Math.round(0.82*w);document.getElementById("canvas").height= Math.round(0.89*h); //Chart1.bounds.x = Math.round(0.01*w);
Chart1.bounds.x = 14;Chart1.bounds.y= 10;
Chart1.bounds.width = Math.round(chartW*w);Chart1.bounds.height= Math.round(0.88*h);
Chart1.legend.visible = false; Chart1.panel.transparent = true;
Chart1.title.visible = false;Chart1.axes.bottom.title.text = " ";
Chart1.axes.left.increment = 1;
Chart1.axes.bottom.increment=1;
Chart1.axes.bottom.innerTicks.visible = true;
Chart1.axes.bottom.ticks.length = 9;
Chart1.axes.bottom.ticks.stroke.fill = "blue";
Chart1.axes.bottom.minorTicks.visible = true;
Chart1.axes.bottom.minorTicks.length = 4;
Chart1.axes.bottom.minorTicks.count = 4;
Chart1.axes.bottom.minorTicks.stroke.fill = "green";
// var dottedLines = Chart1.axes.bottom.increment=.2;
// var increment = 0.20;
// var dottedLines = Chart1.axes.bottom.grid.format.stroke.dash = [5,3];
// var solidLines = Chart1.axes.bottom.increment=1;
// for(increment =0.20;increment<100;increment =increment+0.20){
// if (increment % 1 == 0) {
// Chart1.axes.bottom.increment=1;
// }
// else {
// Chart1.axes.bottom.increment=0.20;
// Chart1.axes.bottom.grid.format.stroke.dash = [5,3];
// }
// }
Chart1.walls.back.format.fill = wallColorCode;
Chart1.walls.back.format.shadow.visible = false;
document.body.style.cursor = "pointer";
document.getElementById("EventCount").value = event_time.length.toFixed(0);
}
Image1:
Image2:
Here an example showing how you could extend the bottom axis adding a new innerGrid property and using it at drawLabel override.
var Chart1;
function draw() {
Chart1 = new Tee.Chart("canvas1");
var line1 = Chart1.addSeries(new Tee.Line());
line1.data.values = [10, 20, 30, 20, 50];
Chart1.legend.visible = false;
Chart1.axes.bottom.setMinMax(0, 5);
Chart1.axes.bottom.increment = 1;
Chart1.axes.bottom.innerTicks.visible = true;
Chart1.axes.bottom.ticks.length = 9;
Chart1.axes.bottom.ticks.stroke.fill = "blue";
Chart1.axes.bottom.minorTicks.visible = true;
Chart1.axes.bottom.minorTicks.length = 4;
Chart1.axes.bottom.minorTicks.count = 4;
Chart1.axes.bottom.minorTicks.stroke.fill = "green";
Chart1.axes.bottom.innerGrid = [];
Chart1.axes.bottom.innerGrid.increment = 0.20;
Chart1.axes.bottom.innerGrid.format = new Tee.Format(Chart1);
Chart1.axes.bottom.innerGrid.format.stroke.fill = Chart1.axes.bottom.grid.format.stroke.fill;
Chart1.axes.bottom.innerGrid.format.stroke.dash = [5, 3];
Chart1.axes.bottom.oldDrawLabel = Chart1.axes.bottom.drawLabel;
Chart1.axes.bottom.drawLabel = function(value, r) {
this.oldDrawLabel(value, r);
var c = this.chart.ctx,
rect = this.chart.chartRect,
f = this.innerGrid.format,
tmpX;
var tmpValue = value + this.innerGrid.increment;
while (tmpValue < value + this.increment) {
tmpX = Chart1.axes.bottom.calc(tmpValue);
if ((tmpX > rect.x) && (tmpX < rect.x + rect.width)) {
c.beginPath();
c.moveTo(tmpX, rect.y);
c.lineTo(tmpX, rect.y + rect.height);
f.stroke.prepare();
c.stroke();
}
tmpValue += this.innerGrid.increment;
}
//draw innerGrid between the axis minimum and the first label. Happens when scrolled
if (value - this.increment <= this.minimum) {
tmpValue = value - this.innerGrid.increment;
while (tmpValue > value - this.increment) {
tmpX = Chart1.axes.bottom.calc(tmpValue);
if ((tmpX > rect.x) && (tmpX < rect.x + rect.width)) {
c.beginPath();
c.moveTo(tmpX, rect.y);
c.lineTo(tmpX, rect.y + rect.height);
f.stroke.prepare();
c.stroke();
}
tmpValue -= this.innerGrid.increment;
}
}
};
Chart1.draw();
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://www.steema.com/files/public/teechart/html5/latest/src/teechart.js" type="text/javascript"></script>
</head>
<body onload="draw()">
<canvas id="canvas1" width="500" height="300">
This browser does not seem to support HTML5 Canvas.
</canvas>
</body>
</html>
Related
OK, so I'm new to JS, so am trying to make the basic 'breakout' game. What I'm trying to do is arrange the bricks into a triangle shape (or more accurately, forming a triangle out of the absence of bricks). But when I choose which items in the 2D array I want to equal 0 (no brick), it only allows me choose one. after that, the game simply won't load.
Weirdest thing is, it will only accept the first line in this part. No matter what I change, the second line onwards will cause the game to not load:
bricks[0][10]=0;
bricks[7][16]=0;
bricks[7][15]=0;
bricks[7][14]=0;
bricks[7][13]=0;
bricks[7][12]=0;
bricks[7][11]=0;
bricks[7][10]=0;
bricks[7][9]=0;
bricks[7][8]=0;
bricks[7][7]=0;
bricks[7][6]=0;
bricks[7][5]=0;
bricks[7][4]=0;
bricks[7][3]=0;
bricks[7][17]=0;
bricks[6][4]=0;
bricks[6][16]=0;
bricks[5][15]=0;
bricks[5][5]=0;
bricks[4][14]=0;
bricks[4][6]=0;
bricks[3][13]=0;
bricks[3][7]=0;
bricks[2][8]=0;
bricks[2][12]=0;
bricks[1][11]=0;
bricks[1][9]=0;
Also, i know the code is incomplete and flawed as it is. It's not finished and still need a lot of polishing up.
Here's my entire code
canvasApp();
function canvasApp(){
var canvas=document.getElementById("canvas")
if (!canvas || !canvas.getContext){
return;
}
var ctx = canvas.getContext("2d");
if (!ctx) {
return
}
//Application States
const GAME_STATE_TITLE = 0;
const GAME_STATE_NEW_LEVEL = 1;
const GAME_STATE_GAME_OVER = 2;
var currentGameState = 0;
var currentGameStateFunction = null;
var brickcount;
var bouncecount = 0;
//Initialise Start Screen State
var titleStarted = false;
var gameStarted = false;
var gameOver = false;
var keyPressList = [];
var keys = false //mouse or keys. false = mouse control, vice versa
var difficulty = 0;
// Declarations for the game
var dx = 6;
var dy = 6;
var x = 150;
var y = 100;
var r = 10;
var WIDTH = 500;
var HEIGHT = 400;
var ballx = 200;
var bally = 200;
var paddlex = WIDTH/1.2;
var paddleh = 10;
var paddlew = 75;
var paddledx = 30
var mouseX;
var bricks;
var NROWS;
var NCOLS;
var BRICKWIDTH;
var BRICKHEIGHT;
var PADDING;
var rowcolours = ["#FF1C0A", "#FFFD0A", "#00A308", "#0008DB", "#EB0093"];
var paddlecolour = "#FF00FF";
var ballcolour = "#00FFFF";
var backcolour = "#0000FF";
function initbricks() {
NROWS = 9
NCOLS = 21
brickcount = NROWS*NCOLS;
BRICKWIDTH = (WIDTH/NCOLS) - 1;
BRICKHEIGHT = 10;
PADDING = 1;
bricks = new Array(NROWS);
for (i=0; i < NROWS; i++) {
bricks[i] = new Array(NCOLS);
for (j=0; j < NCOLS; j++) {
bricks[i][j] = 1;
}
bricks[0][10]=0;
bricks[7][16]=0;
bricks[7][15]=0;
bricks[7][14]=0;
bricks[7][13]=0;
bricks[7][12]=0;
bricks[7][11]=0;
bricks[7][10]=0;
bricks[7][9]=0;
bricks[7][8]=0;
bricks[7][7]=0;
bricks[7][6]=0;
bricks[7][5]=0;
bricks[7][4]=0;
bricks[7][3]=0;
bricks[7][17]=0;
bricks[6][4]=0;
bricks[6][16]=0;
bricks[5][15]=0;
bricks[5][5]=0;
bricks[4][14]=0;
bricks[4][6]=0;
bricks[3][13]=0;
bricks[3][7]=0;
bricks[2][8]=0;
bricks[2][12]=0;
bricks[1][11]=0;
bricks[1][9]=0;
}
}
initbricks();
function switchGameState(newState) {
currentGameState = newState;
switch (currentGameState) {
case GAME_STATE_TITLE:
currentGameStateFunction = gameStateTitle;
break;
case GAME_STATE_NEW_LEVEL:
currentGameStateFunction = gameStatePlayLevel;
break;
case GAME_STATE_GAME_OVER:
currentGameStateFunction = gameStateGameOver;
break;
}
}
function gameStateTitle(){
if (titleStarted != true){
ctx.fillStyle = '#000000';
ctx.fillRect(0,0,500,400);
ctx.fillStyle = '#ffffff';
ctx.font = '20px _sans';
ctx.textBaseline = 'top';
ctx.fillText ("Breakout!", 200,150);
ctx.fillText ("Press Space to Play", 170,200);
if (keys == 0 ) {
ctx.fillText ("Mouse selected", 180,250);
ctx.fillText ("Press k to switch to keys", 140,300);
} else {
ctx.fillText ("Keys selected", 190,250);
ctx.fillText ("Press m to switch to mouse", 140,300);
}
titleStarted = true;
}else{
if (keyPressList[75] == true){
keys = 1;
titleStarted = false;
gameStateTitle(); // Redraw the title page
}
if (keyPressList[77] == true){
keys = 0;
titleStarted = false;
gameStateTitle();
}
if (keyPressList[32] == true){
switchGameState(GAME_STATE_NEW_LEVEL);
titleStarted = false;
}
}
}
function gameStatePlayLevel(){
ctx.fillStyle = '#000000';
ctx.fillRect(0,0,500,400);
ctx.fillStyle = '#ffffff';
// Update the game state and check for game over
function update() {
x+=dx
y+=dy
if (keys == 0) {
paddlex = mouseX;
}else{
if (keyPressList[37]==true){
paddlex-=paddledx;
}
if (keyPressList[39]==true){
paddlex+=paddledx;
}
}
//have we hit a brick?
rowheight = BRICKHEIGHT + PADDING;
colwidth = BRICKWIDTH + PADDING;
row = Math.floor(y/rowheight);
col = Math.floor(x/colwidth);
//if so, reverse the ball and mark the brick as broken
if (y < NROWS * rowheight && row >= 0 && col >= 0 && bricks[row][col] == 1) {
dy = -dy;
bricks[row][col] = 0;
brickcount--;
if (brickcount == 0) {
switchGameState(GAME_STATE_NEW_LEVEL);
difficulty+=1;
initbricks();
x=250;
y=200 + (difficulty*20);
brickcount=NROWS*NCOLS;
bouncecount=0;
}
}
if( x<0 || x>WIDTH) dx=-dx;
if( y<0 || y>HEIGHT) dy=-dy;
else if (y + dy > HEIGHT) {
if (x > paddlex && x < paddlex + paddlew) {
dx = 8 * ((x-(paddlex+paddlew/2))/paddlew);
dy = -dy;
bouncecount++;
}
else {
//game over, so stop the animation
switchGameState(GAME_STATE_GAME_OVER);
initbricks();
}
}
}
function render() {
ctx.save();
function circle(x,y,r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2, true);
ctx.fill();
}
function rect(x,y,w,h) {
ctx.beginPath();
ctx.rect(x,y,w,h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
//draw bricks
for (i=0; i < NROWS; i++) {
ctx.fillStyle = rowcolours [i];
for (j=0; j < NCOLS; j++) {
if (bricks[i][j] == 1) {
rect((j * (BRICKWIDTH + PADDING)) + PADDING,
(i * (BRICKHEIGHT + PADDING)) + PADDING, BRICKWIDTH, BRICKHEIGHT);
}
}
}
circle(x, y, 10);
// init_paddle();
ctx.fillStyle = paddlecolour;
rect (paddlex, HEIGHT-paddleh, paddlew, paddleh);
ctx.restore();
show_result()
}
update();
render();
}
function gameStateGameOver(){
if (gameOver != true){
bouncecount=0;
ctx.fillStyle = '#000000';
ctx.fillRect(0,0,500,400);
ctx.fillStyle = '#ffffff';
ctx.font = '20px _sans';
ctx.textBaseline = 'top';
ctx.fillText ("Game over", 200,150);
ctx.fillText ("Press Space to Restart", 160,200);
ctx.fillText ("You completed " + difficulty + " levels", 160,240);
difficulty=0;
gameOver = true;
}else{
if (keyPressList[32] == true){
switchGameState(GAME_STATE_TITLE);
gameOver = false;
}
}
}
function runGame(){
currentGameStateFunction();
}
// Key handler
document.onkeydown = function(e){
e= e?e:window.event;
keyPressList[e.keyCode] = true;
}
document.onkeyup = function(e){
e= e?e:window.event;
keyPressList[e.keyCode] = false;
}
function onMouseMove(evt) {
// Event data passes to this function
mouseX = evt.clientX-canvas.offsetLeft - paddlew/2;
// Assign the relative position of the mouse in the canvas to mouseX
mouseY = evt.clientY-canvas.offsetTop;
//Do the same for mouseY
document.title="("+mouseX+","+mouseY+")";
//Put the mouse X and Y in the title for info
paddlex = mouseX;
// Position the paddle
}
canvas.addEventListener("mousemove",onMouseMove, false);
//Application start
switchGameState(GAME_STATE_TITLE);
const FRAME_RATE = 40;
var intervalTime = 1000/FRAME_RATE;
setInterval(runGame, intervalTime);
function show_result(){
ctx.fillText ("There are " + brickcount + " bricks", 160,200);
ctx.fillText ("Paddle bounces are " + bouncecount , 160,220);
}
}
With proper indenting, your code looks like this:
bricks = new Array(NROWS);
for (i=0; i < NROWS; i++) {
bricks[i] = new Array(NCOLS);
for (j=0; j < NCOLS; j++) {
bricks[i][j] = 1;
}
bricks[0][10]=0;
bricks[7][16]=0;
In other words, you're attempting to access bricks[7] in the very first iteration when only bricks[0] has been created. Properly close the first for loop with a } before running your list of overrides.
The Problem
I am creating a game that involves dodging projectiles. The player is in control of an image of a ship and I dont want the ship to move exactly together as this looks very unrealistic.
The Question
Is there a way to control how fast the image moves, how can i slow the movemnt of the image down?
The Code
var game = create_game();
game.init();
//music
var snd = new Audio("Menu.mp3");
snd.loop = true;
snd.play();
document.getElementById('mute').addEventListener('click', function (evt) {
if ( snd.muted ) {
snd.muted = false
evt.target.innerHTML = 'mute'
}
else {
snd.muted = true
evt.target.innerHTML = 'unmute'
}
})
function create_game() {
debugger;
var level = 1;
var projectiles_per_level = 1;
var min_speed_per_level = 1;
var max_speed_per_level = 2;
var last_projectile_time = 0;
var next_projectile_time = 0;
var width = 600;
var height = 500;
var delay = 1000;
var item_width = 30;
var item_height = 30;
var total_projectiles = 0;
var projectile_img = new Image();
var projectile_w = 30;
var projectile_h = 30;
var player_img = new Image();
var c, ctx;
var projectiles = [];
var player = {
x: 200,
y: 400,
score: 0
};
function init() {
projectile_img.src = "projectile.png";
player_img.src = "player.png";
level = 1;
total_projectiles = 0;
projectiles = [];
c = document.getElementById("c");
ctx = c.getContext("2d");
ctx.fillStyle = "#ff6600";
ctx.fillRect(0, 0, 500, 600);
c.addEventListener("mousemove", function (e) {
//moving over the canvas.
var bounding_box = c.getBoundingClientRect();
player.x = (e.clientX - bounding_box.left) * (c.width / bounding_box.width) - player_img.width / 2;
}, false);
setupProjectiles();
requestAnimationFrame(tick);
}
function setupProjectiles() {
var max_projectiles = level * projectiles_per_level;
while (projectiles.length < max_projectiles) {
initProjectile(projectiles.length);
}
}
function initProjectile(index) {
var max_speed = max_speed_per_level * level;
var min_speed = min_speed_per_level * level;
projectiles[index] = {
x: Math.round(Math.random() * (width - 2 * projectile_w)) + projectile_w,
y: -projectile_h,
v: Math.round(Math.random() * (max_speed - min_speed)) + min_speed,
delay: Date.now() + Math.random() * delay
}
total_projectiles++;
}
function collision(projectile) {
if (projectile.y + projectile_img.height < player.y + 74) {
return false;
}
if (projectile.y > player.y + 74) {
return false;
}
if (projectile.x + projectile_img.width < player.x + 177) {
return false;
}
if (projectile.x > player.x + 177) {
return false;
}
return true;
}
function maybeIncreaseDifficulty() {
level = Math.max(1, Math.ceil(player.score / 10));
setupProjectiles();
}
function tick() {
var i;
var projectile;
var dateNow = Date.now();
c.width = c.width;
for (i = 0; i < projectiles.length; i++) {
projectile = projectiles[i];
if (dateNow > projectile.delay) {
projectile.y += projectile.v;
if (collision(projectile)) {
initProjectile(i);
player.score++;
} else if (projectile.y > height) {
initProjectile(i);
} else {
ctx.drawImage(projectile_img, projectile.x, projectile.y);
}
}
}
ctx.font = "bold 24px sans-serif";
ctx.fillStyle = "#ff6600";
ctx.fillText(player.score, c.width - 50, 50);
ctx.fillText("Level: " + level, 20, 50);
ctx.drawImage(player_img, player.x, player.y);
maybeIncreaseDifficulty();
requestAnimationFrame(tick);
}
return {
init: init
};
}
https://jsfiddle.net/a6nmy804/4/ (Broken)
Throttle the player's movement using a "timeout" countdown
Create a global var playerFreezeCountdown=0.
In mousemove change player.x only if playerFreezeCountdown<=0.
If playerFreezeCountdown>0 you don't change player.x.
If playerFreezeCountdown<=0 you both change player.x and also set playerFreezeCountdown to a desired "tick timeout" value: playerFreezeCountdown=5. This timeout will cause prevent the player from moving their ship until 5 ticks have passed.
In tick, always decrement playerFreezeCountdown--. This will indirectly allow a change to player.x after when playerFreezeCountdown is decremented to zero or below zero.
You may have played Snake, a game where you have to eat food to grow and you fail if you collide with the snake's body or certain obstacles. The first part was easy, but the latter seems impossible to achieve.
I have tried to make a for loop check if the last element of my snake array is colliding with its other parts. My condition was like this: if the x position of the last item in my array is bigger than any of the array items' x position, and smaller than their x position plus their width, and so on. That didn't work.
Here's my code :
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="myCanvas" width="200px" height="200px" style="border:1px solid black"/>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var yPos = 20;
var width = 15;
var variable = 1;
var currentDir = 1;
//var xPos = (width+5)*variable;
var xPos = 20;
var myArr = [{myX:xPos,myY:yPos},{myX:xPos,myY:yPos},{myX:xPos,myY:yPos}];
var downPressed = false;
var upPressed = false;
var leftPressed = false;
var rightPressed = false;
var first = [0,20,40,60,80,100,120,140,160,180];
var firstX = Math.floor(Math.random()*10);
var firstY = Math.floor(Math.random()*10);
var okayed = first[firstX];
var notOkayed = first[firstY];
var maths = myArr[myArr.length-1];
function drawFood() {
ctx.beginPath();
ctx.rect(okayed,notOkayed,15,15);
ctx.fillStyle = "red";
ctx.fill();
ctx.closePath();
}
function drawRectangle() {
ctx.clearRect(0,0,200,200);
drawFood();
for(var i = 0;i<myArr.length;i++) {
ctx.beginPath();
ctx.rect(myArr[i].myX,myArr[i].myY,width,15);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
}
requestAnimationFrame(drawRectangle);
}
setInterval("calledin()",100);
function calledin() {
var secondX = Math.floor(Math.random()*10);
var secondY = Math.floor(Math.random()*10);
var newobj = {myX:myArr[myArr.length-1].myX+20,myY:myArr[myArr.length-1].myY};
var newobjTwo = {myX:myArr[myArr.length-1].myX,myY:myArr[myArr.length-1].myY+20};
var newobjLeft = {myX:myArr[myArr.length-1].myX-20,myY:myArr[myArr.length-1].myY};
var newobjUp = {myX:myArr[myArr.length-1].myX,myY:myArr[myArr.length-1].myY-20};
var okayNewObj = {myX:myArr[1].myX - 20,myY:myArr[1].myY};
if(myArr[myArr.length-1].myX > 180 || myArr[myArr.length-1].myX < 0 || myArr[myArr.length-1].myY > 180 || myArr[myArr.length-1].myY < 0)
{alert("Game Over");window.location.reload();}
if(myArr[myArr.length-1].myX > okayed-5 && myArr[myArr.length-1].myX < okayed+20 && myArr[myArr.length-1].myY < notOkayed+20 &&
myArr[myArr.length-1].myY > notOkayed-5) {
okayed = first[secondX];
notOkayed = first[secondY];
myArr.unshift(okayNewObj);
}
if(currentDir == 1) {
myArr.push(newobj);
myArr.shift();}
if(currentDir == 2) {
myArr.push(newobjTwo);
myArr.shift();
}
if(currentDir == 4) {
myArr.push(newobjLeft);
myArr.shift();
}
if(currentDir == 3) {
myArr.push(newobjUp);
myArr.shift();
}
for(var i = 0;i<myArr.length-2;i++) {
if(myArr[myArr.length-1].myX > myArr[i].myX &&
myArr[myArr.length-1].myX < myArr[i].myX + 15 && myArr[myArr.length-1].myY > myArr[i].myY && myArr[myArr.length-1].myY > myArr[i].myY + 15)
{alert("Game over");window.location.reload();}
}
}
function downed(e) {
if(e.keyCode==40) {if(currentDir != 3) {currentDir = 2;}}
if(e.keyCode==38) {if(currentDir != 2) {currentDir = 3;}}
if(e.keyCode==39) {if(currentDir != 4) {currentDir = 1;}}
if(e.keyCode==37) {if(currentDir != 1) {currentDir = 4;}}
}
function upped(e) {
if(e.keyCode == 40) {downPressed = false;}
}
document.addEventListener("keydown",downed,false);
document.addEventListener("keyup",upped,false);
drawRectangle();
</script>
</body>
</html>
Suppose the snake is represented by an array called snake in which the head is at index snake.length - 1. We have to compare the position of the head against the positions of the body segments at indices 0 through snake.length - 2.
The following code sets okay to false if the snake head has collided with a body segment. Otherwise, okay remains true.
var head = snake[snake.length - 1],
x = head.x,
y = head.y,
okay = true;
for (var i = snake.length - 2; i >= 0; --i) {
if (snake[i].x == x && snake[i].y == y) {
okay = false;
break;
}
}
Below is a snippet in which I have modified your code to clarify the game logic and to simplify many of the calculations.
Instead of working directly with canvas coordinates, I represent each position with the column index x and row index y of a virtual grid cell. This lets us calculate the neighboring grid positions by adding 1 or -1 to x or y. When it comes time to paint the canvas, we multiply the virtual coordinates by the cell size.
I have replaced most of your literal values with variables. For example, instead of setting the canvas dimensions to 200 by 200, we can do this:
canvas.width = numCols * cellSize;
canvas.height = numRows * cellSize;
This lets us change numCols and numRows in one place to resize the whole game grid. All the calculations work out because they evaluate variables instead of using literals.
I altered the key-event handling to recognize the key codes for the W-A-S-D keys in addition to the arrow keys. When the game is embedded in a long web page, as it is here, you'll probably want to use the W-A-S-D keys so that the page doesn't scroll up and down while you're playing.
var canvas,
ctx,
currentDir,
startX = 1,
startY = 1,
startSnakeLength = 3,
snake,
cellSize = 18,
cellGap = 1,
foodColor = '#a2302a',
snakeBodyColor = '#2255a2',
snakeHeadColor = '#0f266b',
numRows = 10,
numCols = 10,
canvasWidth = numCols * cellSize,
canvasHeight = numRows * cellSize;
var food = {};
function placeFood() {
// Find a random location that isn't occupied by the snake.
var okay = false;
while (!okay) {
food.x = Math.floor(Math.random() * numCols);
food.y = Math.floor(Math.random() * numRows);
okay = true;
for (var i = 0; i < snake.length; ++i) {
if (snake[i].x == food.x && snake[i].y == food.y) {
okay = false;
break;
}
}
}
}
function paintCell(x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x * cellSize + cellGap,
y * cellSize + cellGap,
cellSize - cellGap,
cellSize - cellGap);
}
function paintCanvas() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
paintCell(food.x, food.y, foodColor);
var head = snake[snake.length - 1];
paintCell(head.x, head.y, snakeHeadColor);
for (var i = snake.length - 2; i >= 0; --i) {
paintCell(snake[i].x, snake[i].y, snakeBodyColor);
}
}
function updateGame() {
var head = snake[snake.length - 1],
x = head.x,
y = head.y;
// Move the snake.
var tail = snake.shift();
switch (currentDir) {
case 'up':
snake.push(head = { x: x, y: y - 1 });
break;
case 'right':
snake.push(head = { x: x + 1, y: y });
break;
case 'down':
snake.push(head = { x: x, y: y + 1 });
break;
case 'left':
snake.push(head = { x: x - 1, y: y });
break;
}
paintCanvas();
x = head.x;
y = head.y;
// Check for wall collision.
if (x < 0 || x >= numCols || y < 0 || y >= numRows) {
stopGame('wall collision');
return;
}
// Check for snake head colliding with snake body.
for (var i = snake.length - 2; i >= 0; --i) {
if (snake[i].x == x && snake[i].y == y) {
stopGame('self-collision');
return;
}
}
// Check for food.
if (x == food.x && y == food.y) {
placeFood();
snake.unshift(tail);
setMessage(snake.length + ' segments');
}
}
var dirToKeyCode = { // Codes for arrow keys and W-A-S-D.
up: [38, 87],
right: [39, 68],
down: [40, 83],
left: [37, 65]
},
keyCodeToDir = {}; // Fill this from dirToKeyCode on page load.
function keyDownHandler(e) {
var keyCode = e.keyCode;
if (keyCode in keyCodeToDir) {
currentDir = keyCodeToDir[keyCode];
}
}
function setMessage(s) {
document.getElementById('messageBox').innerHTML = s;
}
function startGame() {
currentDir = 'right';
snake = new Array(startSnakeLength);
snake[snake.length - 1] = { x: startX, y: startY };
for (var i = snake.length - 2; i >= 0; --i) {
snake[i] = { x: snake[i + 1].x, y: snake[i + 1].y + 1 };
}
placeFood();
paintCanvas();
setMessage('');
gameInterval = setInterval(updateGame, 200);
startGameButton.disabled = true;
}
function stopGame(message) {
setMessage(message + '<br> ended with ' + snake.length + ' segments');
clearInterval(gameInterval);
startGameButton.disabled = false;
}
var gameInterval,
startGameButton;
window.onload = function () {
canvas = document.getElementById('gameCanvas'),
ctx = canvas.getContext('2d');
canvas.width = numCols * cellSize;
canvas.height = numRows * cellSize;
Object.keys(dirToKeyCode).forEach(function (dir) {
dirToKeyCode[dir].forEach(function (keyCode) {
keyCodeToDir[keyCode] = dir;
})
});
document.addEventListener("keydown", keyDownHandler, false);
startGameButton = document.getElementById('startGameButton');
startGameButton.onclick = startGame;
}
body {
font-family: sans-serif;
}
#gameCanvas {
border: 1px solid #000;
float: left;
margin-right: 15px;
}
#startGameButton, #messageBox {
font-size: 16px;
margin-top: 15px;
}
#messageBox {
line-height: 24px;
}
<canvas id="gameCanvas"></canvas>
<button id="startGameButton">Start game</button>
<div id="messageBox"></div>
I am trying to have a line draw to the canvas over a certain amount of time(ten seconds to be exact). I'm able to see that the script is counting to a certain time and then stopping, but I'm not seeing the line being drawn. Can anyone show me what I'm doing wrong?
$(document).ready(function(){
canvas = document.getElementById("test");
ctx = canvas.getContext("2d");
var count = 0;
var start_x = 0;
var start_y = 100;
var end_x = 50;
var end_y = 100;
var counter = setInterval(countNumbers, 1000);
ctx.beginPath();
ctx.moveTo(start_x, start_y);
console.log("Start");
function countNumbers(){
count += 1;
ctx.lineTo((start_x + count), start_y);
console.log(count);
if((start_x == end_x) || (count == 10)){
clearInterval(counter);
console.log("End");
}
}
ctx.lineWidth = 5;
ctx.strokeStyle = "white";
ctx.stroke();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="test"></canvas>
Try to move stroke inside the Interval. Because in your case stroke are called immediately without lineTo data. And after that lineTo are called in interval function and cannot be rendered without stroke.
$(document).ready(function(){
canvas = document.getElementById("test");
ctx = canvas.getContext("2d");
var count = 0;
var start_x = 0;
var start_y = 100;
var end_x = 50;
var end_y = 100;
var counter = setInterval(countNumbers, 1000);
ctx.beginPath();
ctx.moveTo(start_x, start_y);
console.log("Start");
function countNumbers(){
count += 1;
ctx.lineTo((start_x + count), start_y);
console.log(count);
if((start_x == end_x) || (count == 10)){
clearInterval(counter);
console.log("End");
ctx.lineWidth = 5; // <----- move here
ctx.strokeStyle = "white";
ctx.stroke();
}
}
})
Also ensure that you are not drawing white lines on white background
$(document).ready(function(){
canvas = document.getElementById("test");
ctx = canvas.getContext("2d");
var count = 0;
var start_x = 0;
var start_y = 100;
var end_x = 50;
var end_y = 100;
var counter = setInterval(countNumbers, 1000);
ctx.beginPath();
ctx.moveTo(start_x, start_y);
console.log("Start");
ctx.lineWidth = 5;
ctx.strokeStyle = "black";
function countNumbers(){
count += 1;
ctx.lineTo((start_x + count), start_y);
ctx.stroke();
console.log(count);
if((start_x == end_x) || (count == 10)){
clearInterval(counter);
console.log("End");
ctx.strokeStyle = "white";
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="test"></canvas>
I would count down for the step. This will allow you to figure out the step.
I modified your code to allow you to pass parameters into the interval function to minimize global scope variables. Since I passed a reference of the interval into itself, you no longer need to have global variables.
I created two function, the first will create a path and then stroke it. The second one will stroke a sub-line after each tick of the interval. I added a simple check for even-odd to swap between colors.
$(document).ready(function() {
var canvas = $('canvas#test')[0];
var ctx = canvas.getContext('2d');
var count = 10;
var start_x = 50, start_y = 50;
var end_x = 250, end_y = 150;
var delta_x = end_x - start_x, delta_y = end_y - start_y;
var step_x = delta_x / count, step_y = delta_y / count;
canvas.width = 300;
canvas.height = 200;
// Fill canvas with solid black.
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'black';
ctx.fill();
// Kick off the line stroke timer. No more global variables!
var counter = setInterval(function(opts) {
// Pass a reference to the timer into the interval.
strokeLineTimerLive(counter, opts);
}, 500, {
ctx : ctx,
n : count,
x1 : start_x,
y1 : start_y,
x2 : end_x,
y2 : end_y,
dx : step_x,
dy : step_y,
});
// After the interval has ended, the path is finally stroked.
function strokeLineTimer(timer, opts) {
if (!opts.init) {
console.log("Start");
opts.ctx.beginPath();
opts.ctx.moveTo(opts.x1, opts.y1);
opts.ctx.lineWidth = 5;
opts.ctx.strokeStyle = 'white';
opts.init = true;
}
opts.n -= 1;
opts.ctx.lineTo((opts.x1 += opts.dx), (opts.y1 += opts.dy));
console.log(opts.n);
if ((opts.x1 == opts.x2) || (opts.n == 0)){
clearInterval(timer);
opts.ctx.stroke();
console.log("End");
}
}
// After each tick of the interval, a line is stroked.
function strokeLineTimerLive(timer, opts) {
if (!opts.init) {
console.log("Start");
opts.ctx.beginPath();
opts.ctx.moveTo(opts.x1, opts.y1);
opts.ctx.lineWidth = 5;
opts.init = true;
}
opts.n -= 1;
opts.ctx.strokeStyle = opts.n % 2 == 0 ? 'white' : 'red';
opts.ctx.lineTo((opts.x1 += opts.dx), (opts.y1 += opts.dy));
opts.ctx.stroke();
console.log(opts.n);
if ((opts.x1 == opts.x2) || (opts.n == 0)){
clearInterval(timer);
console.log("End");
} else {
opts.ctx.beginPath();
opts.ctx.moveTo(opts.x1, opts.y1);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="test"></canvas>
I am trying to make this game, you should not collide the falling object. I have the objects falling and I have my black square, but it flashes when I run it and Im not sure how to make the code stop when the two objects collide together.
here is the code that I have so far!
<html>
<body>
<canvas id="canvasRegn" width="600" height="450"style="margin:100px;"></canvas>
<script>
var ctx;
var imgBg;
var imgDrops;
var noOfDrops = 50;
var fallingDrops = [];
function drawBackground(){
ctx.drawImage(imgBg, 0, 0); //Background
}
function draw() {
drawBackground();
for (var i=0; i< noOfDrops; i++)
{
ctx.drawImage (fallingDrops[i].image, fallingDrops[i].x, fallingDrops[i].y); //The rain drop
fallingDrops[i].y += fallingDrops[i].speed; //Set the falling speed
if (fallingDrops[i].y > 480) { //Repeat the raindrop when it falls out of view
fallingDrops[i].y = -25 //Account for the image size
fallingDrops[i].x = Math.random() * 800; //Make it appear randomly along the width
}
}
}
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
imgBg = new Image();
imgBg.src = "http://www.hamdancommunications.com/HComm/img/wite%20square.png";
setInterval(draw, 36);
for (var i = 0; i < noOfDrops; i++) {
var fallingDr = new Object();
fallingDr["image"] = new Image();
fallingDr.image.src = 'http://s18.postimg.org/o6jpmdf9x/Line1.jpg';
fallingDr["x"] = Math.random() * 800;
fallingDr["y"] = Math.random() * 5;
fallingDr["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr);
anotherGame();
}
}
}
setup();
function anotherGame(){
var canvas = document.getElementById("canvasRegn");
var ctx = canvas.getContext('2d');
canvas.addEventListener("mousedown", clicked);
canvas.addEventListener("mousemove", moved);
canvas.addEventListener("mouseup", released);
var isclicked = 0;
var square = new Object();
square.color = "black";
square.x = 100;
square.y = 100;
square.w = 50;
square.h = 50;
var offX = 0;
var offY = 0;
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = square.color;
ctx.fillRect(square.x,square.y,square.w,square.h);
}
function game(){
}
function clicked(e){
var x = e.offsetX;
var y = e.offsetY;
if(x >= square.x && x <= square.x + square.w &&
y >= square.y && y <= square.y + square.h){
isclicked = 1;
offX = x - square.x;
offY = y - square.y;
}
}
function moved(e){
if(isclicked == 1){
var x = e.offsetX;
var y = e.offsetY;
square.x = x - offX;
square.y = y - offY;
}
}
function released(e){
var x = e.offsetX;
var y = e.offsetY;
isclicked = 0;
}
var drawtimer = setInterval(draw, 1000/30);
var gametimer = setInterval(game, 1000/10);
}
</script>
</body>
</html>