Creating a Rainbow Effect in Rectangle Canvas - javascript

I would like to know how to create a rainbow effect in my canvas in the fill style, like for it to change colors at certain intervals or when I continually press a key. Like from red to blue, etc, similar to how you can add a rainbow effect to text.
<script type="text/javascript">
var GAME_SPEED = 1000/60; //game rate
var x = 100;
var y = 100;
var sideLength = 10;
var leftKey = false;
var rightKey = false;
var upKey = false;
var downKey = false;
var spaceKey = false;
window.onload = function()
{
c = document.getElementById("marCanvas2");
c.width = window.innerWidth*0.9;
c.height = window.innerHeight*0.9;
window.setInterval("draw()" , GAME_SPEED);
}
document.onkeyup = function(event)
{
switch(event.keyCode)
{
case 37: leftKey =false;
break;
case 39: rightKey = false;
break;
case 38: upKey = false;
break;
case 40: downKey = false;
break;
case 32: spaceKey = false;
break;
}
}
document.onkeydown = function(event)
{
switch(event.keyCode)
{
case 37: leftKey =true;
break;
case 39: rightKey = true;
break;
case 38: upKey = true;
break;
case 40: downKey = true;
break;
case 32: spaceKey = true;
break;
}
}
function draw()
{
if(leftKey == true)
{
x--;
}
if(rightKey == true)
{
x++;
}
if(upKey == true)
{
y--;
}
if(downKey == true)
{
y++;
}
if(spaceKey == true)
{
sideLength++;
}
var c = document.getElementById("marCanvas2");
var cntxt = c.getContext("2d");
cntxt.fillStyle= " ";
cntxt.fillRect(x, y, sideLength, sideLength);
}
</script>
</head>
<body>
<!--Marlon Jacques -->
<canvas id="marCanvas2" style="border: 5px solid
#000000;">
Your browser does not support the canvas element.
</canvas>
</body>
</html>

You can do this by dynamically defining the start and end of the gradient. What colors you want is up to you, but you can use for example HSL color model to "rotate" through a color range with different speed for start and end.
Example 1
var ctx = document.querySelector("canvas").getContext("2d"),
angleA = Math.random() * 360, // start angle (for HSL)
angleB = Math.random() * 360,
stepA = 1.2, stepB = 0.7; // "speed" for change
function createGradient() {
var gr = ctx.createLinearGradient(0, 0, 500, 0); // create gradient
gr.addColorStop(0, "hsl(" + (angleA % 360) + ",100%, 50%)"); // start color
gr.addColorStop(1, "hsl(" + (angleB % 360) + ",100%, 50%)"); // end color
ctx.fillStyle = gr; // set as fill style
ctx.fillRect(0, 0, 500, 150); // fill area
}
// demo loop
(function anim() {
createGradient();
ctx.clearRect(8,8,484,134);
// =========> DRAW YOUR FRONT OBJECTS HERE <=========
angleA += stepA; // increase angles
angleB += stepB;
requestAnimationFrame(anim)
})();
<canvas width=500></canvas>
In the demo above the start and end colors are more or less random, you can instead just give one a head start so the other follows:
Example 2
var ctx = document.querySelector("canvas").getContext("2d"),
angle = Math.random() * 360, // start angle (for HSL)
angleDlt = 60, // 60° ahead
step = 1; // "speed" for change
function createGradient() {
var gr = ctx.createLinearGradient(0, 0, 500, 0); // create gradient
gr.addColorStop(0, "hsl(" + (angle % 360) + ",100%, 50%)"); // start color
gr.addColorStop(0.5, "hsl(" + ((angle + (angleDlt/2)) % 360) + ",100%, 50%)");
gr.addColorStop(1, "hsl(" + ((angle + angleDlt) % 360) + ",100%, 50%)");
ctx.fillStyle = gr; // set as fill style
ctx.fillRect(0, 0, 500, 150); // fill area
}
// demo loop
(function anim() {
createGradient();
ctx.clearRect(8,8,484,134);
angle += step; // increase angles
requestAnimationFrame(anim)
})();
<canvas width=500></canvas>

Related

Continuously drawing rectangles in JavaScript canvas slows the program after a few seconds

Right now I'm trying to make a simple 2D platformer in JavaScript canvas. This is what I have so far:
<!DOCTYPE html>
<html>
<body>
<style>
canvas{
background: #eee;
}
</style>
<canvas id="ctx" tabindex=0 width=900 height=500 style="border:1px solid #000000;" onkeypress="movePlayer(event)" onkeyup="keyUp(event)"></canvas>
<script>
var canvas = document.getElementById("ctx");
var ctx = canvas.getContext("2d");
canvas.setAttribute('tabindex', 0);
canvas.focus();
canvas.addEventListener("keydown", movePlayer);
//Maybe I can get a class working?
function Platform(x,y,xSize,ySize){
this.xPos = x;
this.yPos = y;
ctx.fillStyle = "red";
ctx.fillRect(x,y,xSize,ySize);
this.getX = function(){
return this.xPos;
};
this.getY = function(){
return this.yPos;
};
this.getxSize = function(){
return this.xSize;
};
this.getySize = function(){
return this.ySize;
};
}
//Function arrays?
platformArray = [];
//Too many vars smh:
var x_previous = 50;
var y_previous = 50;
var x_new = 50;
var y_new = 50;
var isJumping = false;
var isColliding = false;
var right = false;
var left = false;
var up = false;
var down = false;
var speed = 5;
function movePlayer(event) {
switch(event.keyCode){
//Right
case 39:
right = true;
break;
//Left
case 37:
left = true;
break;
//Up
case 38:
isJumping = true;
up = true;
break;
}
}
function keyUp(event){
switch(event.keyCode){
//Up key up:
case 38:
isJumping = false;
up = false;
break;
//Right key up:
case 39:
right = false;
break;
//Left key up:
case 37:
left = false;
break;
//Down key up:
case 40:
down = false;
break;
}
}
setInterval(update,1);
setTimeout(update,1)
function boundsIntersect(x1,y1,x2,y2){
if(x1 > x2-20 && x1 < x2+200 && y1 < y2 && y1 > y2-55){
return true;
}
return false;
}
function update(){
ctx.clearRect(0,0,900,500)
ctx.fillStyle = "black";
ctx.beginPath();
ctx.fillRect(x_new,y_new,50,50);
//Draw ground:
ctx.beginPath();
ctx.rect(0,490,900,10);
ctx.fillStyle = "green";
ctx.fill();
if(right == true){
x_new+=speed;
x_previous=x_new-speed;
} else if(left == true){
x_new-=speed;
x_previous=x_new-speed;
} else if(down == true){
y_new+=speed;
y_previous=y_new-speed;
} else if(up == true){
y_new-=speed;
y_previous=y_new-speed;
}
if(y_new < 440 && isJumping == false && isColliding == false){
y_new+=5;
y_previous=y_new-5;
}
//Platforms:
platform1 = new Platform(50,300,200,10);
platformArray.push(platform1);
platform2 = new Platform(300,200,200,10);
platformArray.push(platform2);
platform3 = new Platform(400,300,200,10);
platformArray.push(platform3);
//Platform intersections:
platformArray.forEach(function(platform){
if(boundsIntersect(x_new,y_new,platform.getX(), platform.getY()) && isJumping == false){
isColliding = true;
y_new -= 0.5;
} else if(boundsIntersect(x_new,y_new,platform.getX(), platform.getY()) && isJumping == true){
isJumping = false;
y_new += 10;
isColliding = true;
} else {
isColliding = false;
}
});
ctx.save();
ctx.restore();
}
update();
</script>
</body>
</html>
The program runs just fine up until right around the 20sec mark, then it starts to run slower and slower until it just barely moves the player anymore.
I've tried every possible solution I've found online, but nothing seems to work. Any help is appreciated!
Instead of using window.interval to redraw the frames, use window.requestAnimationFrame. There is an example there how to use it.
What you're doing is trying to redraw the frames every 1/1000 of second, which is way too fast anyway.
What window.requestAnimationFrame does is it smartly requests new frames to redraw as needed, in order to maintain a smooth animation.

Snake moves horizontally

I am trying to create a simple snake game.
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
size_x = 10;
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10 == food_position_x) {
size_x += 2;
//throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, 10);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
jsfiddle
The problem
Every time when I catch the food, the snake becomes longer but when you press the down or up key, it moves horizontally.
Maybe a solution
This is what I believe the solution could be:
The snake should be an array! Every time when the key is pressed, define the position of HEAD of snake and move the snake step by step, because it is an array. So the body follows the head. But in this case, I have no idea how to make an array from it.
Maybe there are other solutions. Any helps would be appreciated!
You need to maintain an array of the points currently occupied by the snake body, and add new point (unshift) to the array as the snake approaches and remove point from the back of the array (pop). The following code is a starter, you need to make it your own :).
(function () {
const COLORS={ SNAKE:'#ff7bf5', FOOD:'blue' };
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var snake=[], score=0;
var x, y, food_position_x, food_position_y, x_move, y_move;
var frameCount=0, framesRequiredToMove=10;
//the less the framesToMove the faster the sname moves
function draw(){
if(++frameCount==framesRequiredToMove){
frameCount=0;
move();
}
requestAnimationFrame(draw);
}
function init(){
snake = [{x:3,y:0},{x:2,y:0},{x:1,y:0},{x:0,y:0}];
snake.forEach((p)=>{plot(p.x,p.y,COLORS.SNAKE)})
x=snake[0].x;y=snake[0].y;
score=0;x_move=1;y_move=0;
scoreboard.innerText=score;
newfood();
setTimeout(draw,1000);
}
function plot(x,y,color){
ctx.beginPath();
ctx.rect(x * 10, y * 10, 10, 10);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
}
function move(){
snakepx.innerText = x;
snakepy.innerText = y;
x = x + x_move;
y = y + y_move;
// Advance The Snake
plot(x,y,COLORS.SNAKE);
snake.unshift({x:x,y:y});
// Check food encounter
if(x==food_position_x && y==food_position_y){
scoreboard.innerText=++score;
newfood();
}
else{
var last=snake.pop();
ctx.clearRect(last.x * 10, last.y * 10, 10, 10);
}
}
function newfood(){
food_position_x=Math.floor(Math.random() * canvas.width / 10);
food_position_y=Math.floor(Math.random() * canvas.height / 10);
plot(food_position_x,food_position_y,COLORS.FOOD);
foodpx.innerText = food_position_x;
foodpy.innerText = food_position_y;
}
init();
// Key Pressing
document.addEventListener('keydown', function (event) {
event.preventDefault();
switch (event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = 1;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = 1;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -1;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -1;
y_move = 0;
}
break;
}
});
})();
canvas {
background-color: #000022;
float: left;
}
<canvas id="canvas" width="400" height="180"></canvas>
<div style="margin-left: 410px">
Snake: (<span id="snakepx"></span>, <span id="snakepy"></span>)<br>
Food: (<span id="foodpx"></span>, <span id="foodpy"></span>)<br>
Score: <span id="scoreboard"></span>
</div>
Well as I had some free time to spare I created my own JS snake to demonstrate you how it can be done. Most important parts are in this.snakeBody where array of body is stored and this.moveForward() where you can see how body is updated.
https://jsfiddle.net/nooorz24/p8xtdv3h/13/
moveForward: function() {
var next = this.getNextfieldValue();
if (next == "frame" || next == "body") {
console.log("You lose!")
this.isAlive = false;
} else {
var newHead = this.getNextfieldCoords();
this.draw.snake(newHead.x, newHead.y);
this.body.unshift(newHead);
if (next == "food") {
this.generateFood();
this.snakeSize++;
} else {
var last = this.body.pop();
this.draw.empty(last.x, last.y);
}
}
},
I tried to make it as readable as I could, but note that this is unfinished example and would need need loads of improvements to be a playable game
I think that you have hit on the answer with an array. In the past, I have found that Snake works best with an array, tracking each block of the snake and checking for any two blocks being in the same position. For movement, however, you must directly control the head, and have the body follow based on the position of the array space one ahead of it. The snake head would be the first item in the array. I am not sure what you mean about not understanding the implementation of the array, but the coordinates for each block would be an item in the array.
Have a length variable and make that the x or y size based on direction, like this:
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2,
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
size_x = 10,
size_y = 10,
snake_length = 10;
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10 == food_position_x) {
snake_length += 2;
//throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, size_y);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
size_x = 10;
size_y = snake_length;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
size_x = snake_length;
size_y = 10;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
size_x = 10;
size_y = snake_length;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
size_x = snake_length;
size_y = 10;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
I make the game using C++ soi can advice make a new object for every snake tile and on move set it to parent position
function Tile(x, y)
{
this.x = x;
this.y = y;
}
To debug your down or up problem, I would add some console.log('message') calls in your code for debugging.
Specifically, add some console messages in the switch statement so that you know the correct event and branch is firing. For Example:
switch(event.keyCode) {
case 40:
console.log('down');
...
case 39:
console.log('right');
...
}
Then add more and more debugging log messages until you find your problem.
You can view the console messages in the F12 developer tools in your browser of choice while running your game.
Also make sure you are not calling ctx.translate(...) on the canvas context to flip the canvas, this would change the direction of the x and/or y axis.

increment then decrement radius of arc canvas html5

hi i am trying to gat an arc to resize as it moves across the screen.
I cant seem to asign the value of increment to the radius of the arc for it to get bigger and then smaller.
please see below for the code block in question and then the entire code.
resize(){
this.up = true;
this.r = 0;
this.increment = 10;
this.ceiling = 100;
function PerformCalc() {
if (this.up == true && this.r <= this.ceiling) {
this.r += increment
if (this.r == ceiling) {
this.up = false;
}
} else {
this.up = false
this.r -= increment;
if (this.r == 0) {
this.up = true;
}
}
console.log(this.r);
}
setInterval(PerformCalc, 1000);
}
When i log out the radius to the console it gives nan for some reason.
Any help would be greatly appreciated.
<!DOCTYPE html>
<html>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style type="text/css">
canvas {
border: 1px solid grey;
}
</style>
</head>
<body>
<canvas id="canvas-for-ball"></canvas>
<script type="text/javascript">
// Gets a handle to the element with id canvasOne.
var canvas = document.getElementById("canvas-for-ball");
// Get a 2D context for the canvas.
var ctx = canvas.getContext("2d");
function init(){
canvas.width = 500;
canvas.height = 500;
}
init();
//angle defining spin and sections of ball
var theta = 0;
//for the sections of the ball
var theta2 = 0;
//fort he amount of sections needed
var seventh = (Math.PI*2)/7
//to control the amount of spin the ball has
var thetaInc = 0.0029;
//ball object
class Ball {
constructor(x,y,r,xvel,yvel,mass){
this.x =x;
this.y = y;
this.r =r;
this.xvel = xvel;
this.yvel = yvel;
this.mass = mass;
}
draw(){
// Update the y location.
this.x = this.x + this.xvel;
this.y = this.y + this.yvel;
//draw circle
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.stroke();
//fill the circle
ctx.fillStyle = "orange";
ctx.fill();
//draw inner circle of ball
ctx.beginPath();
ctx.arc(this.x,this.y,this.r*.9,0,Math.PI*2,false);
ctx.stroke();
//spin control
theta += thetaInc;
//loop for adding sections to pie
for( var n = 0; n < 7; ++n) { // add loop to draw radii
theta2 = theta + n * seventh;
ctx.moveTo( this.x, this.y);
ctx.lineTo( this.x + this.r*Math.cos(theta2), this.y + this.r*Math.sin(theta2));
}
ctx.lineWidth = "2";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.stroke();
}
move(){
//condition take into account the this.r of the ball so
//it bounces at the edge of the canvas instead
//of going off of the screen to its center point.
if(this.y > canvas.height - this.r || this.y - this.r <0){
this.yvel = -1*this.yvel;
//to reverse the direction of the ball when hitting walls
if((this.xvel<0 && this.yvel >0) && thetaInc <0){
thetaInc = -1*thetaInc;
}
else if((this.xvel <0 && this.yvel>0) && thetaInc >0){
thetaInc = -1*thetaInc
}
else if((this.xvel >0 && this.yvel >0) && thetaInc >0){
thetaInc = -1 * thetaInc;
}
else if((this.xvel > 0 && this.yvel < 0)&& thetaInc <0){
thetaInc = -1 * thetaInc;
}
}
if(this.x > canvas.width - this.r || this.x - this.r < 0){
this.xvel = -1*this.xvel;
}
}
resize(){
this.up = true;
this.r = 0;
this.increment = 10;
this.ceiling = 100;
function PerformCalc() {
if (this.up == true && this.r <= this.ceiling) {
this.r += increment
if (this.r == ceiling) {
this.up = false;
}
} else {
this.up = false
this.r -= increment;
if (this.r == 0) {
this.up = true;
}
}
console.log(this.r);
}
setInterval(PerformCalc, 1000);
}
colour(){
}
}
//Intersect function takes a ball as a perameter
//ball will be the the object used to test if the two are touching.
function intersect(ball,ball1) {
//the x and y cordinates of the first ball are subtracted from the test ball and stored
//in productX and productY
var productX = ball1.x - ball.x;
var productY = ball1.y - ball.y;
//pythagoras theorem is used to get the distance between both center points of each circle.
var distance = Math.sqrt(productX * productX + productY * productY);
//A condition is used to check if the distance between both bencer point of each circle
//is less than or equal to the sum of both radii the circles are touching.
//the result is p[rinted out to the console
if (distance <= (ball1.r + ball.r)) {
dx = ball.x-ball1.x;
dy = ball.y-ball1.y;
collision_angle = Math.atan2(dy,dx);
magnitude_1 = Math.sqrt(ball.xvel*ball.xvel+ball.yvel*ball.yvel);
magnitude_2 = Math.sqrt(ball1.xvel*ball1.xvel+ball1.yvel*ball1.yvel);
direction_1 = Math.atan2(ball.yvel, ball.xvel);
direction_2 = Math.atan2(ball1.yvel, ball1.xvel);
new_xvel_1 = magnitude_1 * Math.cos(direction_1-collision_angle);
new_yvel_1 = magnitude_1 * Math.sin(direction_1-collision_angle);
new_xvel_2 = magnitude_2 * Math.cos(direction_2-collision_angle);
new_yvel_2 = magnitude_1 * Math.sin(direction_2-collision_angle);
final_xvel_1 = ((ball.mass-ball1.mass)*new_xvel_1+(ball1.mass+ball1.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_xvel_2 = ((ball.mass+ball.mass)*new_xvel_1+(ball1.mass-ball.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_yvel_1 = new_yvel_1;
final_yvel_2 = new_yvel_2;
ball.xvel = Math.cos(collision_angle)*final_xvel_1+Math.cos(collision_angle+Math.PI/2)*final_yvel_1;
ball.yvel = Math.sin(collision_angle)*final_xvel_1+Math.sin(collision_angle+Math.PI/2)*final_yvel_1;
ball1.xvel = Math.cos(collision_angle)*final_xvel_2+Math.cos(collision_angle+Math.PI/2)*final_yvel_2;
ball1.yvel = Math.sin(collision_angle)*final_xvel_2+Math.sin(collision_angle+Math.PI/2)*final_yvel_2;
}
}
canvas.addEventListener("click", function(event) {
var clickX = event.clientX - canvas.offsetLeft;
var clickY = event.clientY- canvas.offsetTop;
b1.x = clickX;
b1.y = clickY;
});
// Add a Javascript event listener to the keypress event.
window.addEventListener("keypress", function(event) {
// Just log the event to the console.
console.log(event);
});
//keypresses with jQuery
$(document.body).on('keydown', function(e) {
console.log(e.which);
switch (e.which) {
// key code for left arrow
case 37:
console.log('left arrow key pressed!');
b1.xvel --;
break;
//keycode for up
case 38:
console.log('up key pressed');
b1.yvel++;
break;
//key code for right
case 39:
console.log('right arrow key pressed!');
b1.xvel++;
break;
//key code for down
case 40:
console.log('down arrow key pressed!');
b1.yvel--;
break;
//key code for + key to increase spin
case 107:
console.log('down arrow key pressed!');
thetaInc +=.001;
break;
//key code for - key to decrease spin
case 109:
console.log('down arrow key pressed!');
thetaInc -=.001;
break;
}
});
b1 = new Ball(200,200,40,1,1,50);
b2 = new Ball(100,100,40,2,2,5);
b1.resize();
// A function to repeat every time the animation loops.
function repeatme() {
//clear canvas for each frame of the animation.
ctx.clearRect(0,0,500,500);
// Draw the ball (stroked, not filled).
b1.draw();
b2.draw();
b1.move();
b2.move();
intersect(b1,b2);
//put repeatme function into the animation frame and store it in animate
animate = window.requestAnimationFrame(repeatme);
}
// Get the animation going.
repeatme();
</script>
</body>
</html>
There is a reference error for increment, e.g. you didn't use this.increment, same for ceiling, should be this.ceiling.
this is used by the setInterval so you save this as that so you can use them. this removes the NaN.
<!DOCTYPE html>
<html>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style type="text/css">
canvas {
border: 1px solid grey;
}
</style>
</head>
<body>
<canvas id="canvas-for-ball"></canvas>
<script type="text/javascript">
// Gets a handle to the element with id canvasOne.
var canvas = document.getElementById("canvas-for-ball");
// Get a 2D context for the canvas.
var ctx = canvas.getContext("2d");
function init(){
canvas.width = 500;
canvas.height = 500;
}
init();
//angle defining spin and sections of ball
var theta = 0;
//for the sections of the ball
var theta2 = 0;
//fort he amount of sections needed
var seventh = (Math.PI*2)/7
//to control the amount of spin the ball has
var thetaInc = 0.0029;
//ball object
class Ball {
constructor(x,y,r,xvel,yvel,mass){
this.x =x;
this.y = y;
this.r =r;
this.xvel = xvel;
this.yvel = yvel;
this.mass = mass;
}
draw(){
// Update the y location.
this.x = this.x + this.xvel;
this.y = this.y + this.yvel;
//draw circle
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.stroke();
//fill the circle
ctx.fillStyle = "orange";
ctx.fill();
//draw inner circle of ball
ctx.beginPath();
ctx.arc(this.x,this.y,this.r*.9,0,Math.PI*2,false);
ctx.stroke();
//spin control
theta += thetaInc;
//loop for adding sections to pie
for( var n = 0; n < 7; ++n) { // add loop to draw radii
theta2 = theta + n * seventh;
ctx.moveTo( this.x, this.y);
ctx.lineTo( this.x + this.r*Math.cos(theta2), this.y + this.r*Math.sin(theta2));
}
ctx.lineWidth = "2";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.stroke();
}
move(){
//condition take into account the this.r of the ball so
//it bounces at the edge of the canvas instead
//of going off of the screen to its center point.
if(this.y > canvas.height - this.r || this.y - this.r <0){
this.yvel = -1*this.yvel;
//to reverse the direction of the ball when hitting walls
if((this.xvel<0 && this.yvel >0) && thetaInc <0){
thetaInc = -1*thetaInc;
}
else if((this.xvel <0 && this.yvel>0) && thetaInc >0){
thetaInc = -1*thetaInc
}
else if((this.xvel >0 && this.yvel >0) && thetaInc >0){
thetaInc = -1 * thetaInc;
}
else if((this.xvel > 0 && this.yvel < 0)&& thetaInc <0){
thetaInc = -1 * thetaInc;
}
}
if(this.x > canvas.width - this.r || this.x - this.r < 0){
this.xvel = -1*this.xvel;
}
}
resize(){
var that = this;
that.up = true;
that.r = 0;
that.increment = 10;
that.ceiling = 100;
function PerformCalc() {
if (that.up == true && that.r <= that.ceiling) {
that.r += that.increment
if (that.r == that.ceiling) {
that.up = false;
}
} else {
that.up = false
that.r -= that.increment;
if (that.r == 0) {
that.up = true;
}
}
console.log(that.r);
}
setInterval(PerformCalc, 1000);
}
colour(){
}
}
//Intersect function takes a ball as a perameter
//ball will be the the object used to test if the two are touching.
function intersect(ball,ball1) {
//the x and y cordinates of the first ball are subtracted from the test ball and stored
//in productX and productY
var productX = ball1.x - ball.x;
var productY = ball1.y - ball.y;
//pythagoras theorem is used to get the distance between both center points of each circle.
var distance = Math.sqrt(productX * productX + productY * productY);
//A condition is used to check if the distance between both bencer point of each circle
//is less than or equal to the sum of both radii the circles are touching.
//the result is p[rinted out to the console
if (distance <= (ball1.r + ball.r)) {
dx = ball.x-ball1.x;
dy = ball.y-ball1.y;
collision_angle = Math.atan2(dy,dx);
magnitude_1 = Math.sqrt(ball.xvel*ball.xvel+ball.yvel*ball.yvel);
magnitude_2 = Math.sqrt(ball1.xvel*ball1.xvel+ball1.yvel*ball1.yvel);
direction_1 = Math.atan2(ball.yvel, ball.xvel);
direction_2 = Math.atan2(ball1.yvel, ball1.xvel);
new_xvel_1 = magnitude_1 * Math.cos(direction_1-collision_angle);
new_yvel_1 = magnitude_1 * Math.sin(direction_1-collision_angle);
new_xvel_2 = magnitude_2 * Math.cos(direction_2-collision_angle);
new_yvel_2 = magnitude_1 * Math.sin(direction_2-collision_angle);
final_xvel_1 = ((ball.mass-ball1.mass)*new_xvel_1+(ball1.mass+ball1.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_xvel_2 = ((ball.mass+ball.mass)*new_xvel_1+(ball1.mass-ball.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_yvel_1 = new_yvel_1;
final_yvel_2 = new_yvel_2;
ball.xvel = Math.cos(collision_angle)*final_xvel_1+Math.cos(collision_angle+Math.PI/2)*final_yvel_1;
ball.yvel = Math.sin(collision_angle)*final_xvel_1+Math.sin(collision_angle+Math.PI/2)*final_yvel_1;
ball1.xvel = Math.cos(collision_angle)*final_xvel_2+Math.cos(collision_angle+Math.PI/2)*final_yvel_2;
ball1.yvel = Math.sin(collision_angle)*final_xvel_2+Math.sin(collision_angle+Math.PI/2)*final_yvel_2;
}
}
canvas.addEventListener("click", function(event) {
var clickX = event.clientX - canvas.offsetLeft;
var clickY = event.clientY- canvas.offsetTop;
b1.x = clickX;
b1.y = clickY;
});
// Add a Javascript event listener to the keypress event.
window.addEventListener("keypress", function(event) {
// Just log the event to the console.
console.log(event);
});
//keypresses with jQuery
$(document.body).on('keydown', function(e) {
console.log(e.which);
switch (e.which) {
// key code for left arrow
case 37:
console.log('left arrow key pressed!');
b1.xvel --;
break;
//keycode for up
case 38:
console.log('up key pressed');
b1.yvel++;
break;
//key code for right
case 39:
console.log('right arrow key pressed!');
b1.xvel++;
break;
//key code for down
case 40:
console.log('down arrow key pressed!');
b1.yvel--;
break;
//key code for + key to increase spin
case 107:
console.log('down arrow key pressed!');
thetaInc +=.001;
break;
//key code for - key to decrease spin
case 109:
console.log('down arrow key pressed!');
thetaInc -=.001;
break;
}
});
b1 = new Ball(200,200,40,1,1,50);
b2 = new Ball(100,100,40,2,2,5);
b1.resize();
// A function to repeat every time the animation loops.
function repeatme() {
//clear canvas for each frame of the animation.
ctx.clearRect(0,0,500,500);
// Draw the ball (stroked, not filled).
b1.draw();
b2.draw();
b1.move();
b2.move();
intersect(b1,b2);
//put repeatme function into the animation frame and store it in animate
animate = window.requestAnimationFrame(repeatme);
}
// Get the animation going.
repeatme();
</script>
</body>
</html>

a border where you can not go through (canvas game)

I have to make a game for school :)
I'am a beginner in Javascript (and English) and I have a question about a canvas.
I made a spaceship in my canvas, and I can fly around with it with my arrowkeys. The problem is that my spaceship can fly trough the border of my canvas.. and thats not way it ment to be.
I hope one of you guys can help me with it! :)
Here is my code..
window.onload = init;
var ctx;
var x = 750;
var y = 400;
var up = false;
var right = false;
var left = false;
var gravity = -1.1;
var horizontalSpeed = 0.1;
function init() {
document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp;
var canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");
animate();
}
function animate() {
moveShip();
drawScene();
requestAnimationFrame(animate);
}
function drawScene(){
ctx.clearRect(0,0,1600,800);
drawSpaceship();
}
function moveShip() {
if (left) {
horizontalSpeed -= 0.1;
}else if (right){
horizontalSpeed += 0.1;
}
if (up) {
gravity -=0.4;
}
gravity += 0.12;
y += gravity;
x += horizontalSpeed;
}
function drawSpaceship () {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, -40);
ctx.lineTo(30,-80);
ctx.lineTo(60,-40);
ctx.lineTo(60,0);
ctx.lineTo(80,30);
ctx.lineTo(80,90);
ctx.lineTo(60,50);
ctx.lineTo(0,50);
ctx.lineTo(-20,90);
ctx.lineTo(-20,30);
ctx.lineTo(0,0);
ctx.strokeStyle = 'white';
ctx.stroke();
ctx.closePath();
ctx.restore();
}
function handleKeyDown (evt) {
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
left = true;
break;
case 38:
up = true;
break;
case 39:
right = true;
break;
}
}
function handleKeyUp(evt) {
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
left = false;
break;
case 38:
up = false;
break;
case 39:
right = false;
break;
}
}
You need a concept called "clamping".
Clamping is limiting a value within a specified range.
You want to clamp your ship's horizontal position to be no less than 0 and no greater than the canvas width.
You want to clamp your ship's vertical position to be no less than 0 and no greater than the canvas height.
This is code to clamp a value between a min and max value.
clampedValue = Math.min(Math.max(currentValue, min), max);
To keep any [x,y] within the canvas, you can clamp the x,y like this:
clampedX = Math.min(Math.max(x, 0), canvasWidth);
clampedY = Math.min(Math.max(y, 0), canvasHeight);
Now your ship is larger than just a single [x,y] point. So to keep your entire ship inside your canvas you would clamp the [x,y] like this:
y += gravity;
x += horizontalSpeed;
x=Math.min(Math.max(x,0+20),width-80);
y=Math.min(Math.max(y,0+80),height-90);
Also, you're letting gravity increase even if you ship is on the ground. At that point the gravity effect becomes zero because the ship is being entirely supported by the ground against gravity. Therefore, you'll want to set gravity to zero when the ship is on the ground:
if(y==height-90){gravity=0;}
Here's your code refactored to keep your ship inside the canvas:
var x = 200;
var y = 100;
var up = false;
var right = false;
var left = false;
var gravity = -1.1;
var horizontalSpeed = 0.1;
var canvas = document.querySelector("canvas");
var width=canvas.width;
var height=canvas.height;
var ctx = canvas.getContext("2d");
init();
function init() {
document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp;
animate();
}
function animate() {
moveShip();
drawScene();
requestAnimationFrame(animate);
}
function drawScene(){
ctx.clearRect(0,0,1600,800);
drawSpaceship();
}
function moveShip() {
if (left) {
horizontalSpeed -= 0.1;
}else if (right){
horizontalSpeed += 0.1;
}
if (up) {
gravity -=0.4;
}
gravity += 0.12;
y += gravity;
x += horizontalSpeed;
x=Math.min(Math.max(x,0+20),width-80);
y=Math.min(Math.max(y,0+80),height-90);
if(y==height-90){gravity=0;}
}
function drawSpaceship () {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, -40);
ctx.lineTo(30,-80);
ctx.lineTo(60,-40);
ctx.lineTo(60,0);
ctx.lineTo(80,30);
ctx.lineTo(80,90);
ctx.lineTo(60,50);
ctx.lineTo(0,50);
ctx.lineTo(-20,90);
ctx.lineTo(-20,30);
ctx.lineTo(0,0);
ctx.strokeStyle = 'blue';
ctx.stroke();
ctx.closePath();
ctx.restore();
}
function handleKeyDown (evt) {
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
left = true;
break;
case 38:
up = true;
break;
case 39:
right = true;
break;
}
}
function handleKeyUp(evt) {
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
left = false;
break;
case 38:
up = false;
break;
case 39:
right = false;
break;
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>Hold down the arrow keys to move the ship.</h4>
<canvas id="canvas" width=500 height=400></canvas>

How do I get rid of the trail of images that are drawn as my character moves?

How do I get rid of the trail of images that are drawn as my character moves?
var avatarX = 0; //Variable
var avatarY = 267; //Variable
var avatarImage; //Variable
var counter = 1; //Variable
var XWIDTH = 0; //Variable
var WIDTH = 400; //Variable
var dx = 5; //Variable
var tt; //Variable
Code to set up the game canvas
window.addEventListener('keydown', KeyDown);
function setUpGame() {
var gameCanvas = document.getElementById("gameCanvas");
avatarImage = new Image();
avatarImage.src = "img/avatar.png";
gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, avatarY);
var tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
Code to detect button presses
function KeyDown(evt, switchTEMPO) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
}
break;
case 37: /*Arrow to the right*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
}
break;
}
}
Code to implement a counter
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
gameCanvas.width = 400;
gameCanvas.getContext("2d").font = "18px Iceland";
gameCanvas.getContext("2d").textBaseline = "top";
gameCanvas.getContext("2d").fillText("Seconds: " + counter, 5, 5);
}
}
Code to draw character to the screen
function handleTick() {
gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
}
You're probably not clearing the canvas. Before drawing the next frame, you should do the following:
// Clear a specific area of the context
context.clearRect (x, y, width, height);
For example, if your canvas has a width of 300px and a height of 100px,
context.clearRect(0, 0, 300, 100);

Categories