My newest Hobby Project is a very simple Jump'n'Run Game using JavaScript. I already wrote some code (with the help of a tutorial at lostdecadegames) and read everything about the GameLoop.
var start = true;
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1200;
canvas.height = 480;
document.body.appendChild(canvas);
var jumping = false;
var gravity = 1.5;
var pressed = true;
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "background.png";
// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "hero.png";
// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function () {
monsterReady = true;
};
monsterImage.src = "monster.png";
// Game objects
var hero = {
speed_x: 50,
speed_y_up: 50,
speed_y_down: 50, // movement in pixels per second
velocity_x: 50,
velocity_y: 50
};
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
// Update game objects
var update = function (modifier) {
if(38 in keysDown) { // Player holding up
jumping = true;
//hero.y -= hero.speed_y_up * modifier;
}
if (40 in keysDown) { // Player holding down
hero.y += hero.speed_y_down * modifier;
}
if (37 in keysDown) { // Player holding left
hero.x -= hero.speed_x * modifier;
}
if (39 in keysDown) { // Player holding right
hero.x += hero.speed_x * modifier;
}
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (heroReady) {
if(hero.y > 0 && hero.y < 480 && hero.x <= -32)
{
hero.x = hero.x + 1232;
ctx.drawImage(heroImage, hero.x, hero.y);
}
else if(hero.y > 0 && hero.y < 480 && hero.x >= 1200)
{
hero.x = hero.x - 1232;
ctx.drawImage(heroImage, hero.x, hero.y);
}
else if(jumping)
{
ctx.drawImage(heroImage, hero.x, hero.y-100);
jumping = false;
}
else ctx.drawImage(heroImage, hero.x, hero.y);
}
if (monsterReady) {
ctx.drawImage(monsterImage, monster.x, monster.y);
}
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 500);
render();
then = now;
};
// Starting the game!
reset();
var then = Date.now();
setInterval(main, 1); // Execute as fast as possible
As you can see, I already added a fix gravity var and some speed vars. The Hero moves very smooth, so this is no problem.
I have 2 problems with the jump-Animation:
The Hero stays in the air, when the Up-Key is keep being pressed. I tried to fix this with some boolean vars, but I couldn't figure it out how to get the Hero down again.
Right now, I implemented a "dirty hack" which causes the Hero to be repainted 50px higher, but I want a smooth Jump, so that the Hero gets slower while going up and speeds up while falling. I looked up so many Tutorials and so much Example Code, but I'm too stupid to figure it out, how I get my desired Animation.
Hope you guys can give me some advice for my problem (I'm not asking for the final code, I just need some tips).
It's hard to understand exactly what the if statements inside of if (heroReady) are doing because the numbers don't mean anything to me, but it seems to me like your problem is in there.
First of all, it seems to me like jumping should the first condition checked. If one of the first conditions is true, then it doesn't matter whether or not he's jumping. I can't easily tell when each condition is true, though, so I'm going to assume that when the player is holding up,
else if(jumping)
{
ctx.drawImage(heroImage, hero.x, hero.y-100);
jumping = false;
}
gets executed like normal.
Now, assuming that, I think your issue is that jumping is determined solely by whether or not the player is holding up, because as soon as jumping is true, it becomes false. This is incorrect.
Jumping should be set to true when the player presses the up key, but it should be set to false when they remove it. It should be set to false when the animation hits the ground.
Another issue that you have is the fact that you aren't actually using the hero's attributes to render its jumping location, you're simply offsetting it. Perhaps that is just your workaround until the problem is solved, but it makes it hard to tell when the character hits the ground, because you can't start lower the character (increasing the y value) after they jump, since you never raised them by decreasing the y value.
So how do we fix this?
Here are my recommendations. You might find more elegant ways to do it by the time you're done due to refactoring, but the way you have it set up right now I think it will work fine:
Set jumping as soon as they press up, like you're doing, but only if jumping == false, because presumably your hero can't do mid-air jumps.
Immediately after you set jumping (and inside the same if statement), update their velocity.
In your update section, add another if for whether or not the player is jumping, regardless of whether or not they are pressing any keys. If they are, decrease their momentum based on gravity. Then, add a check for if their momentum is the opposite of how much you increase it when they start jumping. In other words, check if they are moving down at exactly the same rate they were moving up when they started jump. This happens at exactly the y-coordinate that they began the jump from. (This is more reliable that just checking their position, because it will work from multiple y-locations.) The alternative would be to store a variable with the y-coordinate they were at when they jumped. Either way, if their jump has ended, set jumping to false.
Since you're updating their coordinates based on jumping, in your render function, you can eliminate any jumping logic and just draw the image based on the coordinates.
Does that help at all?
Related
Here's the site in question: https://marks-groovy-project-2fa056.webflow.io/
I want to rotate each letter by 90 degrees on their Y axis while scroll is active, and return them back to their original position as soon as scrolling stops.
Visualization: in top view, a letter should rotate 90deg counter-clockwise when scroll is activated, which will render the letter invisible in front view ( the viewport) while scrolling, and then turn back 90 degrees clockwise when scrolling ends, so that each letter is visible again.
Method: used skew.js and slightly modified it:
skew.js is applied to an entire section. I want to apply it to every instance of a span with id="letter-animation". I've appropriately renamed the constant and referenced the #.
const speed is a remnant from skew.js. I haven't yet figured out how to rewrite it. It expresses the amount of skew as a function of the difference in newPixel/oldPixel. Which I don't want. My rotation needs to be 90deg every time. Once in, once out.
letter.style.transform = "rotateY(45deg)" used to be "rotateY(" + speed + "deg)" in the old script. (technically it was "skewY", not "rotateY" but you get my point). const speed would then be replaced with whatever new constant is appropriate as mentioned in point 2.
I've set up this codepen to isolate the script in question. https://codepen.io/mhedinger/pen/yLJaLmp
const letter = document.querySelector("#letter-animation")
let currentPixel = window.pageYOffset
const looper = function(){
const newPixel = window.pageYOffset
const diff = newPixel - currentPixel
const speed = diff * 11
letter.style.transform = "rotateY(45deg)"
currentPixel = newPixel
requestAnimationFrame(looper)
}
looper()
Here's the tutorial that explains how skew.js works: https://www.superhi.com/video/skew-on-scroll-effect
And here's an example of it working, according to the video tutorial above: https://codepen.io/emgiust/pen/rdOJwQ
const section = document.querySelector("section");
let currentPixel = window.pageYOffset
//looper keeps running and keeps track of where the new pixel is
const looper = function () {
const newPixel = window.pageYOffset;
const diff = newPixel - currentPixel
const speed = diff * 0.35;
section.style.transform = "skewY(" + speed + "deg)"
currentPixel = newPixel;
requestAnimationFrame(looper)
}
looper();
Can anybody help me get this working? So far, the main issue seems to be that they're spans and not sections, but it could also just be my complete absence of understanding of javascript.
I'm hoping to control the transition speed, curve, and delay via css, but if it has to be controlled in JS, i'd also appreciate some advice on how to do this.
Thank you everyone in advance for trying to help.
Cheers,
Mark
NOTE: there is another script running (fullpage.js) which simulates a swiping experience during scroll. deactivate it temporarily to get a better view of what’s happening during scroll while you’re checking things out/setting things up. End-product, a letter animation that synchronously rotates each letter by 90 degrees (rendering the words invisible) for the duration of the swipe/scroll, and returning them to normal once the section snaps into place.
In case anybody is still interested in this, I have figured it out in the meantime.
const letter = document.getElementsByTagName("SPAN");
var timer = null;
window.addEventListener('scroll', function() {
if(timer !== null) {clearTimeout(timer)}
timer = setTimeout(function() {
var i;
for (i = 0; i < letter.length; i++) {
letter[i].style.transform = "rotateY(0deg)";
};
}, 150);
var i;
for (i = 0; i < letter.length; i++) {
letter[i].style.transform = "rotateY(90deg)";
};
}, false);
https://codepen.io/mhedinger/pen/yLJaLmp
EDIT:
I have improved this script for best-practice purposes. This makes it more stable and versatile because it can now be used together with plugins like fullpage.js. Additionally, if desired, the transforms can now also be called manually by referencing the appropriate function.
let letter = document.getElementsByTagName("SPAN");
var timer = null;
var rotateLetter = function() {
Array.from(letter).forEach(function(letter) {
letter.style.transform = "rotateY(90deg)";
});
};
var resetLetter = function() {
Array.from(letter).forEach(function(letter) {
letter.style.transform = "rotateY(0deg)";
});
};
window.addEventListener('scroll', function() {
if(timer !== null) {clearTimeout(timer)}
timer = setTimeout(function() {resetLetter()}, 125);
rotateLetter()
}, false);
https://codepen.io/mhedinger/pen/dypmKZd
I am trying to make a game. The object of the game is to move the square across the screen without hitting a raindrop falling from the roof. How do i make it so that if one of the raindrops enters the square, the square returns to the beginning of the canvas or x =0. Here is the code:
var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');
var WIDTH = 1000;
var HEIGHT = 700;
var x = 0;
var y = HEIGHT-20;
var xPos = [0];
var yPos = [0];
var speed = [1];
var rainDrops = 50;
var rectWidth = 20;
var rectHeight = 20;
for (var i = 0; i < rainDrops; i++) {
xPos.push(Math.random()* WIDTH);
yPos.push(0);
speed.push(Math.random() * 5);
}
function rainFall () {
window.requestAnimationFrame(rainFall);
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i <rainDrops; i++) {
//Rain
ctx.beginPath();
ctx.arc(xPos[i], yPos[i], 3, 0, 2 * Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
//Rain movement
yPos[i]+=speed[i];
//Box
ctx.fillStyle = 'red';
ctx.fillRect(x, y, rectWidth, rectWidth);
if (yPos[i] > HEIGHT) {
yPos[i]= 0;
yPos[i]+=speed[0];
}
//This is the part where I need the Help!!!!!!!!!
if (){
x = 0;
}
}
};
//Move Object
function move (e) {
if (e.keyCode === 37) {
ctx.clearRect (0, 0, WIDTH, HEIGHT);
x -=10;
}
if (e.keyCode === 39) {
ctx.clearRect (0, 0, WIDTH, HEIGHT);
x+=10;
}
canvas.width=canvas.width
}
//Lockl Screen
window.addEventListener("keydown", function(e) {
// Lock arrow keys
if( [37,39,].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
}, false);
rainFall();
document.onkeydown = move;
window.addEventListener("load", doFirst, false);
Conditional statements
I am never too sure how to answer these types of questions. As you are a beginner I don't want to overwhelm you with code and techniques, but at the same time I don't want to give an answer that perpetuates some bad techniques.
The short answer
So first the simple answer from your code where you wrote
//This is the part where I need the Help!!!!!!!!!
// the test checks the center of the drop
// if drop is greater than > top of player (y) and (&&)
// drop x greater than > left side of player x and (&&) drop is less than <
// right side of player (x + rectWidth) then drop has hit player
if (yPos[i] > y && xPos[i] > x && xPos[i] < x + rectWidth ){
x = 0; // move player back
}
BTW you are drawing the player rectangle for each rain drop. You should move that draw function outside the loop.
The long answer
Hopefully I have not made it too confusing and have added plenty of comments about why I did this and that.
To help keep everything organised I separate out the various elements into their own objects. There is the player, rain, and keyboard handler. This is all coordinated via the mainLoop the is called once a frame (by requestAnimationFrame) and calls the various functions to do all that is needed.
The player object holds all the data to do with the player, and functions to draw and update the player (update moves the player)
The rain object holds all the rain in an array called rain.drops it has functions to draw and update the rain. It also has some functions to randomize a drop, and add new drops.
To test if the rain has hit the player I do it in the rain.update function (where I move the rain) I don`t know what you wanted to happen when the rain hits the player so I just reset the rain drop and added 1 to the hit counter.
I first check if the bottom of the rain drop drop.y + drop.radius is greater than the top of the player if(drop.y + drop.radius >= player.y){
This makes it so we dont waste time checking rain that is above the player.
The I test for the rain in the x direction. The easiest is the test the negative (if the rain is not hitting the player) as the logic is a little simplier.
If the right side of the drop is to the left of the left side of the player, or (use || for or) the left side of the drop is to the right of the right side of the player than the drop can not be hitting the player. As we want the reverse condition we wrap it in a brackets a put a not in front if(! ( ... ) )
The test is a little long so I break it into 2 lines for readability.
// drop is a single rain drop player is the player
if (drop.y + drop.radius >= player.y) {
if ( ! (drop.x + drop.radius < player.x ||
drop.x - drop.radius > player.x + player.width) ) {
// code for player hit by rain in here
}
}
The rain.update function also checks if the rain has hit the bottom of the canvas and resets it if so.
Demo
I copied your code from in the question and modified it.
addEventListener("load",function(){ // you had onload at the bottom after all the code that gets the canvas
// etc. Which kind of makes the on load event pointless. Though not needed
// in this example I have put it in how you can use it for a web page.
// Using onload event lets you put the javascript anywhere in the HTML document
// if you dont use onload you must then only put the javascript after
// the page elements you need eg Canvas.
var canvas = document.getElementById('gameCanvas');
var ctx = canvas.getContext('2d');
ctx.font = "20px arial";
var frameCount = 0; // counts the frames
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var currentMaxDrops = 5; // rain will increase over time
const numberFramesPerRainIncrease = 60 * 5; // long name says it all. 60 frames is one second.
const maxRainDrops = 150; // max number of rain drops
// set up keyboard handler
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
requestAnimationFrame(mainLoop); // request the first frame of the animation (get it all going)
//==========================================================================================
// Setup the keyboard input stuff
const keys = { // list of keyboard keys to listen to by name.
ArrowLeft : false,
ArrowRight : false,
}
function keyEvent(event){ // the key event argument event.code hold the named key.
if(keys[event.code] !== undefined){ // is this a key we want
event.preventDefault(); // prevent default browser action
keys[event.code] = event.type === "keydown"; // true if keydown false if not
}
}
//==========================================================================================
const player = { // object for everything to do with the player
x : 0, // position
y : HEIGHT - 20,
width : 20, // size
height : 20,
speed : 4, // speed per frame
color : "red",
showHit : 0, // when this is > 0 then draw the player blue to indicate a hit.
// This counter is counted down each frame so setting its value
// determins how long to flash the blue
hitCount : 0, // a count of the number of drops that hit the player.
status(){ // uses hit count to get a status string
if(player.hitCount === 0){
return "Dry as a bone.";
}
if(player.hitCount < 5){
return "A little damp.";
}
if(player.hitCount < 15){
return "Starting to get wet.";
}
return "Soaked to the core";
},
draw(){ // draw the player
if(player.showHit > 0){
player.showHit -= 1; // count down show hit
ctx.fillStyle = "blue";
}else{
ctx.fillStyle = player.color;
}
ctx.fillRect(player.x,player.y,player.width,player.height);
},
update(){ // this updates anything to do with the player
// Not sure how you wanted movement. You had it so that you move only when key down events
// so I have done the same
if(keys.ArrowLeft){
player.x -= player.speed; // move to the left
keys.ArrowLeft = false; // turn off the key. If you remove this line then will move left while
// the key is down and stop when the key is up.
if(player.x < 0){ // is the player on or past left side of canvas
player.x = 0; // move player back to zero.
}
}
if(keys.ArrowRight){
player.x += player.speed; // move to the right
keys.ArrowRight = false; // turn off the key. If you remove this line then will move right while
// the key is down and stop when the key is up.
if(player.x + player.width >= WIDTH){ // is the player on or past right side of canvas
player.x = WIDTH - player.width; // move player back to inside the canvas.
}
}
}
}
//==========================================================================================
const rain = { // object to hold everything about rain
numberRainDrops : 50,
drops : [], // an array of rain drops.
randomizeDrop(drop){ // sets a drop to random position etc.
drop.x = Math.random() * WIDTH; // random pos on canvas
drop.y = -10; // move of screen a little so we dont see it just appear
drop.radius = Math.random() *3 + 1; // give the drops a little random size
drop.speed = Math.random() * 4 + 1; // and some speed Dont want 0 speed so add 1
return drop;
},
createDrop(){ // function to create a rain drop and add it to the array of drops
if(rain.drops.length < currentMaxDrops){ // only add if count is below max
rain.drops.push(rain.randomizeDrop({})); // create and push a drop. {} creates an empty object that the function
// randomizeDrop will fill with the starting pos of the drop.
rain.numberRainDrops = rain.drops.length;
}
},
draw(){ // draw all the rain
ctx.beginPath(); // start a new path
ctx.fillStyle = 'blue'; // set the colour
for(var i = 0; i < rain.drops.length; i ++){
var drop = rain.drops[i]; // get the indexed drop
ctx.arc(drop.x, drop.y, drop.radius, 0, 2 * Math.PI);
ctx.closePath(); // stops the drops rendered as one shape
}
ctx.fill(); // now draw all the drops.
},
update(){
for(var i = 0; i < rain.drops.length; i ++){
var drop = rain.drops[i]; // get the indexed drop
drop.y += drop.speed; // move down a bit.
if(drop.y + drop.radius >= player.y){ // is this drop at or below player height
// checks if the drop is to the left or right of the player
// as we want to know if the player is hit we use ! (not)
// Thus the next if statement is if rain is not to the left or to the right then
// it must be on the player.
if(!(drop.x + drop.radius < player.x || // is the rigth side of the drop left of the players left side
drop.x - drop.radius > player.x + player.width)){
// rain has hit the player.
player.hitCount += 1;
player.showHit += 5;
rain.randomizeDrop(drop); // reset this drop.
}
}
if(drop.y > HEIGHT + drop.radius){ // is it off the screen ?
rain.randomizeDrop(drop); // restart the drop
}
}
}
}
function mainLoop () { // main animation loop
requestAnimationFrame(mainLoop); // request next frame (don`t need to specify window as it is the default object)
ctx.clearRect(0, 0, WIDTH, HEIGHT);
frameCount += 1; // count the frames
// when the remainder of frame count and long name var is 0 increase rain drop count
if(frameCount % numberFramesPerRainIncrease === 0){
if(currentMaxDrops < maxRainDrops){
currentMaxDrops += 1;
}
}
rain.createDrop(); // a new drop (if possible) per frame
rain.update(); // move the rain and checks if the player is hit
player.update(); // moves the player if keys are down and check if play hits the side of the canvas
player.draw(); // draw player
rain.draw(); // draw rain after player so its on top.
ctx.fillStyle = "black";
ctx.fillText("Hit " + player.hitCount + " times.",5,20);
ctx.setTransform(0.75,0,0,0.75,5,34); // makes status font 3/4 size and set position to 5 34 so I dont have to work out where to draw the smaller font
ctx.fillText(player.status(),0,0); // the transform set the position so text is just drawn at 0,0
ctx.setTransform(1,0,0,1,0,0); // reset the transform to the default so all other rendering is not effected
};
});
canvas {
border : 2px black solid;
}
<canvas id="gameCanvas" width=512 height=200></canvas>
Hope this was helpfull.
I'm trying to make a basic FPS view using CSS.
Here's a demo of what I have so far: https://jsfiddle.net/w8q7xtmL/
In particular, movement is as simple as detecting keypresses, then:
// "self" is if the player object
requestAnimationFrame(step);
function step() {
if( keys[37]) self.direction += 2;
if( keys[39]) self.direction -= 2;
if( keys[38]) {
self.x += Math.cos(self.direction/180*Math.PI) * 4;
self.y -= Math.sin(self.direction/180*Math.PI) * 4;
}
if( keys[40]) {
self.x -= Math.cos(self.direction/180*Math.PI) * 4;
self.y += Math.sin(self.direction/180*Math.PI) * 4;
}
self.camera.style.transform = "rotateX(90deg) rotateZ("+(self.direction-90)+"deg) translate(-"+self.x+"px,-"+self.y+"px)";
requestAnimationFrame(step);
}
This works quite well, but there are a couple of issues.
Sometimes, elements don't stack correctly. The floor will be visible when walls should be blocking it from view, for instance.
Other times, the view will freeze completely, despite there being no errors in the console or anything that would indicate failure. It just... stops. Sometimes I can get it un-stuck by trying to move around a bit to "unstick" it, but other times I just have to reload the page.
Are there any discernible errors in my approach, or is the state of 3D transforms just not there yet for this kind of thing?
For the record, in case it matters, I'm developing with Google Chrome 49.
I can't believe I missed this.
Before:
self.camera.style.transform = "rotateX(90deg) rotateZ("+(self.direction-90)+"deg)
translate(-"+self.x+"px,-"+self.y+"px)";
After:
self.camera.style.transform = "rotateX(90deg) rotateZ("+(self.direction-90)+"deg)
translate("+(-self.x)+"px,"+(-self.y)+"px)";
Because, funnily enough, when self.x is negative, you get translate(--12px,0px) which is invalid.
I believe it is because you are detecting keys in a loop.
Instead, use this:
var rotval = 0;
window.addEventListener('keydown', function(e) {
key = e.keyCode
if(key === "left")
{
rotval = 1;
}
}, true);
window.addEventListener('keyup', function(e) {
key = e.keyCode
if(key === "left")
{
rotval = 0;
}
}, true);
then just add a variable to the loop function and when it is more or less than 0, it moves or rotates the camera!
function loop()
{
camera.rotation.y += rotval
camera.position.x //and so on
}
setInterval(loop,30)
Hope this helps :)
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';
}
Im currently working on getting my player sprite to move around my screen, but when a key is pressed all the sprite seems to do is disappear! I have no errors coming up in firebug, so i am assuming that the sprite isn't being redrawn correctly or something along those lines.
Here is my code for my player:
function Player()
{
var sprite = new Sprite(),
player,
x,
y,
w = sprite.width,
h = sprite.height,
speed = 4;
this.init_Player = function(pos_X, pos_Y){
player = sprite.load("player");
x = pos_X;
y = pos_Y;
};
this.update = function(delta) {
var calculated_speed = (speed * delta) * (60/1000);
$(document).keydown(function(e)
{
var cancel_default = (e.which === 32 || (e.which > 36 && e.which < 41));
cancel_default && e.preventDefault();
if(e.keyCode == 37){
x -=calculated_speed;
}
else if(e.keyCode == 38){
y -=calculated_speed;
}
else if(e.keyCode == 39){
x +=calculated_speed;
}
else if(e.keyCode == 40){
y +=calculated_speed;
}
});
};
this.draw = function() {
ctx.drawImage(player,x, y, w ,h);
};
}
The player is created in my main game javascript file like so:
player.init_Player(location_X,location_Y);
And then in my main game loop i have the now, delta and last times being made as well as the call to player.update and player.render like so:
function update(){
now = Date.now();
delta = now - last_update;
ctx.clearRect(0,0,canvas.width,canvas.height);
gameGUI.update();
player.update(delta);
player.draw();
last_update = now;
setTimeout(update,1);
}
Like i said at the top, all my sprite does on a key press is disappear. The code you can see above is all the code i have for the player so somewhere in here is the bug!
How would i accomplish making my sprite move on screen with a time-based animation like the one i've set up?
Thanks
EDIT
Also to let you know, i have last_update equal to Date.now() the line before my update call gets made initially like so:
function game_init(state) {
game_settings(state);
last_update = Date.now();
update();
}
Edit 2
On continued inspection, it doesn't seem like the sprite is disappearing after all, just moving very far e.i off the game screen... so another guess is that my calculations are wrong somewhere?
All sorted guys, i have my character moving using this little tutorial! Real easy to read and understand for the beginners out there.
LINK
What do the pros think of this tutorial?