Making a rectangle bounce off a canvas wall - javascript

All I need is to have this object travel left and right across the top of the canvas. Currently it spawns and travels right absolutely fine, then stops once it reaches the right edge of the canvas.
//mainEnemy Variables
var mainEnemy_x = 10;
var mainEnemy_y = 10;
var mainEnemyHeight = 50;
var mainEnemyWidth = 25;
var mainEnemyRight = true;
var mainEnemyLeft = false;
var mainEnemy_dx = 2;
//Drawing the Main Enemy
function drawMainEnemy()
{
ctx.beginPath();
ctx.rect(mainEnemy_x, mainEnemy_y, mainEnemyHeight, mainEnemyWidth);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
}
//Movement speed of mainEnemy
if(mainEnemyRight && mainEnemy_x < canvas.width-mainEnemyWidth)
{
mainEnemy_x += 5;
}
else if(mainEnemyLeft && mainEnemy_x > 0)
{
mainEnemy_x -= 5;
}
//mainEnemy moves across the top of the canvas
if(mainEnemy_x + mainEnemy_dx - mainEnemyWidth > canvas.width)
{
mainEnemy_dx = -mainEnemy_dx;
}
ball_x += dx;
ball_y += dy;
mainEnemy_x += mainEnemy_dx;
}
This is all the code relevant to the object I need help with. I've tried just reversing it's x movement, with the mainEnemy_dx = -mainEnemy_dx; line, but this isn't working. I can see this code is an absolute mess at the moment, I just need to get it working then time for some serious cleanup.
Any and all help would be greatly appreciated!

First of all, you have two movement systems. One with the left and right flags and constants added or subtracted from x and the other with dx. You should just use one or the other, the latter being simpler.
For the jitter, you have to either also check that the current dx is positive when going over the right by border (and negative on left) and then switch the sign, or move the object left when a collision with right border is found.
At the moment you are moving the object 7 units right every time, then when border is found only dx is used (2 or -2) but since your object can be over the border it might vibrate between 2 and -2 always. But at least the right branch will always try to move 5 units right even when dx is negative.
Using a debugger to step through the code and inspecting the variables and branches taken while vibrating on the right edge will show exactly how it behaves.

Related

Colision detection p5.js

just trying to make a simple pong game in p5.js. I have very recently gotten into JavaScript and can't manage to figure out collision detection between the ball and the bat. I have tried a few ways of doing it but it mostly just stopped my code from running.. etc.. would love any help!
Here is my source code:
function setup() {
createCanvas(750, 750);
}
var x = 50;
var y = 50;
var direction = 5;
var arrow = 0;
var ball;
var bat;
function draw() {
background(220);
fill ('white');
ball = ellipse (x, y, 50, 50);
x = x + direction;
if (x > width - 25){
direction = -5;
}
if (x < 25) {
direction = 5;
}
x++;
y++;
if (keyIsDown(RIGHT_ARROW)){
arrow += 7;
}
if (keyIsDown(LEFT_ARROW)){
arrow += -7;
}
fill ('black');
bat = rect(arrow, 600, 150, 15);
}
Your question is pretty broad, but basically what you want to do is imagine a "bounding rectangle" around the ball, and then use rectangle-rectangle collision to check whether the ball is colliding with a paddle. If it is, "bounce" the ball by multiplying its horizontal speed by -1.
I wrote a tutorial on collision detection available here, but the basic if statement looks like this:
if(rectOneRight > rectTwoLeft && rectOneLeft < rectTwoRight && rectOneBottom > rectTwoTop && rectOneTop < rectTwoBottom){
You also might want to read the Collision Detection with Moving Objects section of that tutorial. It's written for Processing, but everything applies to P5.js as well.
If you're having trouble getting it working, then please start over with a more basic sketch that just shows two hard-coded rectangles. Make them turn red when they're not colliding. Then work your way up from there. It's hard to answer general "how do I do this" type questions, so you'll have much better luck if you post a specific "I tried X, expected Y, but got Z instead" type question. Good luck.

Simple canvas animation: 50x50 image moving across

I've done this sort of programming before but It was a long while back, and despite trying for a while now, I am unable to get this working. I've tried loads of other similar codes that I've found on the internet but they don't work exactly the way I want it to! I basically want a 155x55 canvas, with a 50x50 image moving across it, simple! Despite how simple it sounds... I'm struggling... I've tried adapting my previous code but that was for bouncing balls and it was a long time ago. I'll appreciate any help. Thanks!
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
var speed = 1;
a = new Image();
a.src = "http://www.animated-gifs.eu/category_cartoons/avatars-100x100-cartoons-spongebob/0038.gif";
function frameRate(fps) {
timer = window.setInterval( updateCanvas, 1000/fps );
}
function updateCanvas() {
ctx.fillRect(0,0, myCanvas.width, myCanvas.height);
draw();
}
function draw() {
/* Add code here to randomly add or subtract small values
* from x and y, and then draw a circle centered on (x,y).
*/
var x = 0 + speed;
var y = 20;
if (x > 150) {
x == 1;
}
ctx.beginPath();
ctx.drawImage(a,x,y,100,100);
}
/* Begin animation */
frameRate(25);
Fiddle Link:
https://jsfiddle.net/th6fcdr1/
The problem you have is that your variable x and y are always reset to 0 and 20. Your speed is 1 so your x is always 1.
Since you never update the x position and always reset it to 0. What you could do is to increase the variable speed by 1 at the end of the frame.
speed += 1
At first, you'll have:
x = 0 + 1
then
x = 0 + 2
... and so on.
Then you'll have to check for speed being above 150 and reset speed to 1.
Then I suggest renaming speed by posX which is more accurate. Also, instead of using setInterval you should be using requestAnimationFrame(). And instead of incrementing the posX by 1, you should be incrementing the posX by speed * elapsedTime to get a fluent move and stable speed move which doesn't depend on the framerate.
In the end, you'd have this:
posX += speed * elapsedTime
var x = posX

Two sprites collide - which one rear ended the other?

I am writing a simple game (in Javascript) where circular sprites can collide with each other. I store an angle (in degrees) and an x,y for each object. I have the collision detection working, but I need to work out which sprite hit the other. So for two objects colliding which one drove into the other (i.e. the front of which sprite made contact with the 'non front' of the other). Or to put it another way, which one rear ended the other. In the case of very close head on accidents e.g. where they make an absolute direct head on collision (180 degree collision) or are within say 5 degrees of doing so (175-185 degree collision), then I need to spot this and attribute no 'blame' to either sprite. What would the maths, or better still the code, for this be?
var angleA = Math.abs(collidedWith.angle - 180);
var angleB = Math.abs(this.angle - 180);
var angleConsideredHeadOn = 5;
var anglesSubtracted = Math.abs(angleA - angleB);
if (anglesSubtracted < angleConsideredHeadOn) {
var headOn = true;
}
if (anglesSubtracted >= angleConsideredHeadOn) {
// There was a non-head on crash
var xA = collidedWith.velocityX;
var yA = collidedWith.velocityY;
var xB = this.velocityX;
var yB = this.velocityY;
// Need to determine which sprites 'front' collided with the other's side or read
}
To detect the head-on case, take the dot product of their two (pre-impact) velocity vectors which will give you the cosine between their headings. If that value is less than -0.9 Pi then the collision is head on.
Otherwise, the sprite to blame is the one with the highest absolute velocity (since a slow sprite cannot possibly rear-end a fast sprite).
This seems to work...
// Javascript
// Two objects 'this' and 'collidedWith' have collided
// this code determines who head butted the other
// Based on having an angle and an X and Y velocity (xDir and yDir) where volicity could be negative (going left or up) or positive (going right or down)
// 'degrees' is a function which converts radians to degrees
var angleConsideredHeadOn = 15;
var theta_a = degrees(Math.atan2(this.xDir, this.yDir));
var theta_b = degrees(Math.atan2(collidedWith.xDir, collidedWith.yDir));
var a_to_b = degrees(Math.atan2(this.posY - collidedWith.posY, this.posX - collidedWith.posX)); // Normal angle from 'this's perspective
var b_to_a = -a_to_b % 360; // ditto from collidedWith's perspective
var collision_angle_a = Math.abs(theta_a - a_to_b) % 360
var collision_angle_b = Math.abs(theta_b - b_to_a) % 360
// Collision is close to head on
if (Math.abs(collision_angle_a - collision_angle_b) < angleConsideredHeadOn) return;
//
if (collision_angle_a < collision_angle_b) {
// 'collidedWith' head butted the other object
} else {
// 'this' head butted the other object
}

Move canvas object on touchmove in Javascript

I’m fairly new to web development and I’ve only ever used jQuery to write my scripts. Today however, I’d like to improve my skills and build a little game that could be used on a smartphone as a web app in vanilla JS.
The game’s pretty straightforward:
You hold your phone in portrait mode and control a character that stays at the bottom of the screen and has to dodge objects that are falling on him. The character can only move left or right and thus always stays on the same x-axis. In order to control him, your finger has to stay on the screen. Once you take it off, you lose. Also, the move isn’t triggered by tapping the screen, but by moving your finger left or right.
For now, I’ve only been experimenting to get the hang of touchevents and was able to make the character move when swiping:
document.addEventListener('touchmove',function(e){
e.preventDefault(); //disable scroll
var board = document.getElementById(‘board);
var character = document.getElementById(‘character’);
if (e.targetTouches.length === 1) {
var touch = e.targetTouches[0];
board.classList.add(‘moving’);
character.style.left = touch.pageX + 'px';
}
}, false);
(The ‘moving’ class is used to move the background-position of the board and animate the character’s sprite in plain CSS.)
Separately, I made a little script that puts objects with random classes in a container with a set interval. These objects are then animated in css and fall from the top to the bottom of the screen.
Now, here comes the tricky part: the collision detection.
As I said, I’m new to development and vanilla JS, so I searched a bit to figure out how to detect when two objects collide, and it seems that most tutorials do this using canvases. The thing is, I’ve never used them and they scare me quite a bit. What’s more, I think it would render what I’ve done so far useless.
I’m okay with trying the canvas way, but before I do, I’d like to know if there’s any other way to detect if two moving objects collide?
Also, if there turns out to be no real way to do this without canvas, I plan on using this tutorial to learn how to build the app. However, this game wasn’t built for touchscreen devices, and the spaceship’s position changes on certain keystrokes (left & right) :
function update() {
if (keydown.left) {
player.x -= 5;
}
if (keydown.right) {
player.x += 5;
}
player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}
My question is: how should I do to update the position using touchmove instead of keystrokes?
Thank you all in advance.
1) the idea : 'if you stop touching, you loose', is just a bad idea, drop it.
2) most convenient way to control is to handle any touch event (touch start/move/end/cancel), and to have the character align on the x coordinate of this event.
3) the intersection test is just a basic boundig box intersection check.
I made a very basic demo here, that uses touch, but also mouse to ease testing :
http://jsbin.com/depo/1/edit?js,output
a lot of optimisations are possible here, but you will see that touches adjust the ship's position, and that collisions are detected, so it will hopefully lead you to your own solution
Edit : i added default to 0 for left, top, in case they were not set.
boilerplate code :
var collisionDisplay = document.getElementById('collisionDisplay');
// hero ship
var ship = document.getElementById('ship');
ship.onload = launchWhenReady ;
// bad ship
var shipBad = document.getElementById('shipBad');
shipBad.onload = launchWhenReady ;
// image loader
imagesCount = 2 ;
function launchWhenReady() {
imagesCount --;
if (imagesCount) return;
setInterval(animate, 20);
}
var shipBadY = 0;
touch events :
// listen any touch event
document.addEventListener('touchstart', handleTouchEvent, true);
document.addEventListener('touchmove', handleTouchEvent, true);
document.addEventListener('touchend', handleTouchEvent, true);
document.addEventListener('touchcancel', handleTouchEvent, true);
// will adjust ship's x to latest touch
function handleTouchEvent(e) {
if (e.touches.length === 0 ) return;
e.preventDefault();
e.stopPropagation();
var touch = e.touches[0];
ship.style.left = (touch.pageX - ship.width / 2) + 'px';
}
animation :
// animation loop
function animate()  {
// move ship
shipBadY += 1;
shipBad.style.top = Math.ceil(shipBadY) + 'px';
// test collision
var isColliding = testCollide(shipBad);
collisionDisplay.style.display = isColliding ? 'block' : 'none';
}
collision :
// collision test when the enemy and the ship are images
function testCollide(enemi) {
var shipPosX = parseInt(ship.style.left) || 0 ;
var shipPosY = parseInt(ship.style.top) || 0 ;
var shipWidth = ship.width ;
var shipHeight = ship.height;
var badX = parseInt(enemi.style.left) || 0 ;
var badY = parseInt(enemi.style.top) || 0 ;
var badWidth = enemi.width;
var badHeight = enemi.height;
return bBoxIntersect(shipPosX, shipPosY, shipWidth, shipHeight,
badX, badY, badWidth, badHeight);
}
EDIT : in case you're not using images :
// collision test when the enemy and the ship are ** NOT ** images
function testCollide(o) {
var characterPosX = parseInt(character.style.left);
var characterPosY = parseInt(character.style.top);
var characterWidth = parseInt(character.style.width);
var characterHeight = parseInt(character.style.height);
var obstacleX = parseInt(o.style.left) || 0 ;
var obstacleY = parseInt(o.style.top) || 0 ;
var obstacleWidth = parseInt(o.style.width);
var obstacleHeight = parseInt(o.style.height);
return boundingBoxIntersect(characterPosX, characterPosY, characterWidth, characterHeight, obstacleX, obstacleY, obstacleWidth, obstacleHeight);
}
function bBoxIntersect(x1, y1, w1, h1, x2, y2, w2, h2) {
return !(x1 + w1 < x2 || x1 > x2 + w2 || y1 + h1 < y2 || y1 > y2 + w2);
}
mouse events :
// -----------------------------------------------------
// Handle mouse event for easy testing on Browser
document.addEventListener('mousemove', handleMouseEvent);
function handleMouseEvent(e) {
ship.style.left = (e.pageX - ship.width / 2) + 'px';
}

HTML5 canvas character jump

I try to make an animation of character by reading this tutorial:
http://mrbool.com/html5-canvas-moving-a-character-with-sprites/26239 .
It's quite ease to make the character go left ('go right' is already done). But how to make the character jump (with animation)?
I was thinking about something like this:
case 38:
if (y + dy > HEIGHT){
y += dy
}
break;
...but it just move character up (without animation). Can someone help me? Some code example will be useful.
You get the jumping behavior like this (using the same code on the tutorial)
JSFiddle
var canvas;// the canvas element which will draw on
var ctx;// the "context" of the canvas that will be used (2D or 3D)
var dx = 50;// the rate of change (speed) horizontal object
var x = 30;// horizontal position of the object (with initial value)
var y = 150;// vertical position of the object (with initial value)
var limit = 10; //jump limit
var jump_y = y;
var WIDTH = 1000;// width of the rectangular area
var HEIGHT = 340;// height of the rectangular area
var tile1 = new Image ();// Image to be loaded and drawn on canvas
var posicao = 0;// display the current position of the character
var NUM_POSICOES = 6;// Number of images that make up the movement
var goingDown = false;
var jumping;
function KeyDown(evt){
switch (evt.keyCode) {
case 39: /* Arrow to the right */
if (x + dx < WIDTH){
x += dx;
posicao++;
if(posicao == NUM_POSICOES)
posicao = 1;
Update();
}
break;
case 38:
jumping = setInterval(Jump, 100);
}
}
function Draw() {
ctx.font="20px Georgia";
ctx.beginPath();
ctx.fillStyle = "red";
ctx.beginPath();
ctx.rect(x, y, 10, 10);
ctx.closePath();
ctx.fill();
console.log(posicao);
}
function LimparTela() {
ctx.fillStyle = "rgb(233,233,233)";
ctx.beginPath();
ctx.rect(0, 0, WIDTH, HEIGHT);
ctx.closePath();
ctx.fill();
}
function Update() {
LimparTela();
Draw();
}
var Jump = function(){
if(y > limit && !goingDown){
y-=10;
console.log('jumping: ' + y);
} else{
goingDown = true;
y +=10;
if(y > jump_y){
clearInterval(jumping);
goingDown = false;
}
}
}
function Start() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(Update, 100);
}
window.addEventListener('keydown', KeyDown);
Start();
There's no one right answer to this question, and unless you find a game-design library, there's no simple one, either. Your problem is that you're moving the character instantaneously in response to input, but a jump requires movement over time. You'll have to either find a moving sprites library - I don't have one in particular to recommend, but I'm sure Google has several - or set up something yourself that runs every so many milliseconds and updates the character's position and some sort of velocity variable.
Edit: Looking at that tutorial, the simplest solution that comes to mind is to put your animation code inside of Update(), like so:
function Update() {
LimparTela();
Animate();
Draw();
}
Inside of Animate(), you should keep track of the character's height and vertical momentum. If the momentum is positive, increase the y position a little, otherwise decrease it a little. Either way, reduce momentum a bit. Add something to keep the character from going through the floor, and have the up key set the character's momentum to be positive if he's on the floor.
Note that this is an incredibly bare-bones solution, but for a basic tutorial it'll do the job.

Categories