Moving a sprite image using arrow keys in JavaScript - javascript

I have to animate a robo such that it would move around an HTML5 Canvas.
Here's my image: https://i.stack.imgur.com/oecS2.png
The instructions I have to work on my animation are:
If you are not pressing a button, the skeleton should not move and should just be facing you.
If you press the right arrow key or “d” then it should move to the right.
If you press the left arrow key or “a” then it should move to the left.
If you press the up arrow key or “w” then it should move up.
If you press the down arrow key or “s” then it should move down
If it gets to the edge of the canvas, it should keep walking but not move
I haven't been able to find any helpful resources that would guide me to move my sprite image using arrow keys. And I know a bit of making an image move using mouse but not using arrow keys. But here's what I've tried so far.
JavaScript:
var tID;
function stopAnimate()
{
clearInterval(tID);
}
function animateScript()
{
var position = 256;
const diff = 256;
tID = setInterval ( () => {
document.getElementById("image").style.backgroundPosition = `-${position}px 0px`;
if (position < 1536)
{
position = position + diff;
}
else
{
position = 256;
}
}, 100);
}
HTML:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' type='text/css' href='Robot.css'>
</head>
<body>
<h2>Animation</h2>
<div id ="demo">
<p id="image" onmouseover="animateScript()" onmouseout="stopAnimate()"></p>
</div>
<script src="Animate.js"></script>
</body>
</html>
CSS:
body
{
background: white;
color: black;
}
#image
{
height: 256px;
width: 256px;
background: url('robo.png') 0px 0px;
}
The code above isn't the right thing that I need but I was just testing it using my knowledge about moving sprites using a mouse but I need some help on rotating my image using arrow keys. Any help would be appreciated!

Related

How to handle coordinates of map in different display sizes

I have two divs: #wrapper and #map-frame.
The #wrapper has overflow:hidden and size of the window, while #map-frame is %150 size, to give the feeling of zooming into the map.
This map is an image with buildings and houses: I've made an array that has objects with different coordinates.
These coordinates are stored in nested arrays:
[ [0,0],[10,10] ]
So an imaginary box from point x0y0 to x10y10
If when we click, our mouse coordinates are inside of this imaginary box, a function will be run - and it does.. until..
We resize the screen.
The image becomes smaller, so something that would've been at [[329, 461],[684,641]] is now unreachable in an image that on gets to 300...
Here is the code:
var user = {
gold: 20
}
var goTo= function(e){
var frame = document.getElementById("map-frame");
var x = e.offsetX;
var y = e.offsetY;
for(i = 0; i < spots.length; i++){//check for every spot in the map if we are inside the box
var currentSpot = spots[i];
if ( (x > currentSpot.coords[0][0] && y > currentSpot.coords[0][1]) && (x < currentSpot.coords[1][0] && y < currentSpot.coords[1][1]) ){
console.log("Welcome to the " + currentSpot.name);
currentSpot.action()
}
}
frame.style.transform = "translate(-"+x/2+"px,-"+y/2+"px)";//this will center the camera at the point. kind of
}
var spots = [
{
coords: [[30,28],[135,87]],
name: "Farm",
action: function(){
console.log("You enter the farm and are sold some hay")
}
},
{
coords: [[329, 461],[684,641]],
name: "Fish Market",
action: function(){
if(user.gold > 10){
console.log("You buy some fish and lose 10 gold")
user.gold-=10;
}
else {
console.log("You have no gold to buy fish!")
}
}
}
];
And here is the HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Map Navigation</title>
<style>
#wrapper {
width:100vw;
height: 100vh;overflow:hidden;position:relative;
background-image:url("https://wallpapercave.com/wp/XqRBXyO.jpg")
}
#map-frame{
background-image: url('https://i.redd.it/xlolj0bg057z.jpg');
background-repeat: no-repeat;
background-size: contain;
width:150%;
height: 150%;
transition: .2s all ease-in-out;
}
</style>
</head>
<body>
<div id="wrapper" ><div id="map-frame" onclick="goTo(event)"></div> </div>
</body>
</html>
Since I do not have enough reputation to leave a comment I will have to leave an answer. Have you ever looked at leaflet.js? It is a very simple to use javascript library built specificly for this purpose. We use it where I work and it works flawlessly. It however works on latitude and longitude points, so that may not work for you. You can however put jpg's in and work with those, but I have not done any work with that yet.
Another option is to keep track of a ratio to how zoomed in the map is. So, when you zoom in keep track of a ratio to adjust your movement of x and y, and then along with that keep track of where the center of the camera is from the origin to + or - extra from the translation for x and y to get correct movement.
Does this answer your question? It might help if you set the map to a specific height to start the ratio at 100% as well.

How to manipulate divs to render only a few at a time without lag?

I'm not sure if this qualifies as a "unique enough" question, but I've found it to be too specific to find it already answered. I'm attempting to dynamically create a map with block-display-styled divs using JavaScript. To prevent lag, I just want the elements to be created and destroyed as the user "moves the camera" which is really just moving everything one space to any direction, and deleting the row/column that is not visible anymore.
Thus, I have two constructs, one which is data-only, the array that stores the whole map, and another one which represents the plane only the user can see, and is made up of divs.
The problem comes when the map is initially rendered, since the first visible element is NOT the first square of the actual map, but actually an area inside that shares the same middle. See the following image for reference:
for (var n = 0 ; n < map_xy.lenght; n++){ // Will repeat by the number of cells
var newtile = document.createElement('div');
newtile.className = "map_cell";
newtile.id = n.toString();
};
My Question is: How can I make it so that the program knows about the whole map without actually rendering it?. This is something I need, there will be terrain generation that will search for adjacent cells and other similar things.
I don't even know if this is the correct aproach, my goal is to reduce lag as much as posible, so that when a user requests a 1000 by 1000 cell map, he/she can still only see his/her 40~ by 40~ "window", so that the browser won't just crash.
Thanks for your help, I'll edit this if it's unclear in its current state.
I think you're close. I would use a 2-dimensional array to store the whole map, in which case you can use nested loops with pre-defined boundaries on the initial rendering.
var map; // assume this is a 2D array, where each element has a property
//called "tileID", which you want assigned to a corresponding div
for(var x = init_x_left; x < init_x_right; x++){
for(var y = init_y_top; y < init_y_bot; y++){
var newtile = document.createElement('div');
newtile.className = "map_cell";
newtile.id = map[x][y].tileID; // example
}
}
Where init_x_left, init_x_right, init_y_top, init_y_top, enclose the initial area that you want rendered.
The important thing to note here is that the code you posted starts at 0 and goes until map_xy.length, which will make the entire map render every time because you are traversing the whole array. On top of that, you're storing 2D information in a 1D array, and that makes working with that information more complicated than it needs to be, in my opinion, though I suppose it's not impossible?
However, after searching a bit, it doesn't seem like javascript has an easy way of declaring a 2D array, so you would have to write a function to generate and populate one.
Bill mentioned in a comment about virtual lists/DOM, which if done well is probably a more elegant solution than this one, but would present its own challenges as well. If there was a way to find out how Google Maps scrolls seamlessly, I would try to replicate that.
This is not an actual answer, but it does illustrate why the problem exists:
https://jsfiddle.net/atrpm1qy/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Map</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Raleway:400,300,600">
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css">
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">
<style>
#map {
width: 500px;
height: 500px;
overflow: scroll;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.row {
white-space: nowrap;
margin: 0px;
padding: 0px;
font-size: 0;
}
.tile {
display: inline-block;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAALHRFWHRDcmVhdGlvbiBUaW1lAFNhdCAyNCBPY3QgMjAxNSAxMzo1NDo1NCAtMDgwMKYSKEcAAAAHdElNRQffChgUNwUL4zycAAAACXBIWXMAAA9fAAAPXwHXitrJAAAABGdBTUEAALGPC/xhBQAAAyNJREFUeNptls1uE0EQhJfNBlkCyRaKxIqTj+HElWfhcXg6rtw4+pCDLQXJFgkYxULU7rcuV3ozspLZnp6a7uqfmVdfvr5rxrFYvWHS99fb7VMTQxL9TeFuc9Df9+ulFb5/u9en5AiP+0cwO0OjNOovDaHx6fON0bVNynN01IpZwHb8057dZoI7HzNBeBvouYRws29SLiiBSMjo5v7m3C4b7rA/JQnJLd5gqMfVh48jKavu5/bP4/7v7u53Qdee+7tfp+PT+nZ1PF29XS1YlUTQ2mUJwdPnw8O/bvEahA6nZJfp3vwY3LOlDKEnVygc9oeMkBWIiqiW3R38aCYIoAljomeQzcn69tpLhS5JiMQUA2ENsRrRsVTnzfOBAIyCEa6ffBrs7VczD5b61KTF0tHfk6kXotbwlINtI75ihxQst4vssrB1FrGz0MJ+k24d0HW2OUHNqwZpja79CovWyByW8Uy/zMXcb25dJaXgu6T7kuD9EHBIk4LRNSnlitCOuugwUTXRvoAegTW65cz100m5dE6tC8l0pzatMNd0i0Qv4ZGO3IeWuX9acr9pjY6edip/qT48ddXYRR0mnUKdaSmUdBSktElzTWCfUJNIzmBS3oc1s6ZbyHxWaKA35yZRzHEXkbFYAxZ+wAnb9SmLL2maFONpaZ8SJrpDOgKdfD2gUxCGSnZUsctsihxHrNSzGTPX+gkha8UhacmW5nlbL8O5n9DZEN3amunuOnjj0IvMPsu+k+1QMTw5TKwm7i79kHTzzpxDq9l/fBi7jG4nVLp5mw4U8T1edQeK4NKEowPOnxTFGyjyqU7W9kXD6ZQ6r6BjBKB5TLJE0sPt9GyhSdkcV0C+RBD2/U2el+aTZgyjDx7gi1sNer5jaVC0NtoL12GpFV8MVIYbzESR0LUZErmZs9wloZqKmdmahgfHuaPkM1DCrqS/IHz750sLdFeyw4jrbl8ZjCmLbI4vSNdkea2CTtEwwWRfTRk/UmAKsi1CL/klnZq4trIhpu1ZcUZv6KZ4hGlZunmtM4y7WFVJkpMRunSIUs88TEqE5jVvSRZw3vP/ARLfRAcPZyviAAAAAElFTkSuQmCC');
height: 32px;
width: 32px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var rows = 100;
var columns = 100;
var map = document.querySelector('#map');
var row, column, tileRow, tile;
var height = 0;
var width = 0;
function makeRow() {
var div = document.createElement('div');
div.classList.add("row");
return div;
}
function makeTile() {
var div = document.createElement("div");
div.classList.add("tile");
return div;
}
for (row = 0; row < rows; row += 1) {
tileRow = makeRow();
map.appendChild(tileRow);
width = 0;
for (column = 0; column < columns; column += 1) {
tile = makeTile();
tileRow.appendChild(tile);
width += tile.offsetWidth;
}
height += tileRow.offsetHeight;
}
map.scrollTop = height / 2 - map.offsetWidth / 2;
map.scrollLeft = width / 2 - map.offsetHeight / 2;
</script>
</body>
</html>
Get up to very many tiles and the browser gets mighty angry.
I'd probably explore the Canvas tag to draw the map.

Javascript division positioning

Here's my simple code.It contains division, which moves on dragging with mouse (on x axis) anywhere on screen.Everything works perfect on first drag, but on second division comes back to it's original position, which is centre of screen.I know why does this happen, but can't figure out how to fix it.My point is to continue moving division from coords where previous drags moved it.
<!DOCTYPE html>
<html>
<head>
</head>
<body style="overflow:hidden">
<style>
#screen
{
width:200px;
height:300px;
position:absolute;
top:0;bottom:0;left:0;right:0;
margin:auto;
border-style:solid;
}
</style>
<script>
var exit=0;
document.onmousedown=function(e)
{
exit=1;
x=e.pageX;
document.onmousemove= function(e)
{
if(exit==1)
{
y=e.pageX;
final=x-y;
document.getElementById("screen").innerHTML=final;
document.getElementById("screen").style.left=final+"px";
}
};
};
document.onmouseup=function(e)
{
exit=0;
}
</script>
<div id="screen">
</body>
</html>
You want to store the "final" value so that you can use it as an offset on the next click. What's happening is that you are using the mouse down and mousemove X difference to move the object, but on second click you are not taking into consideration that the object was offseted by the previous "final" value and it has to be moved with that offset in mind!
Here's the code snippet working, and the jsfiddle link below:
var exit=0;
var final = 0;
document.onmousedown=function(e)
{
exit=1;
x=e.pageX + final;
document.onmousemove= function(e)
{
if(exit==1)
{
y=e.pageX;
final=x-y;
document.getElementById("screen").innerHTML=final;
document.getElementById("screen").style.left=final+"px";
}
};
};
document.onmouseup=function(e)
{
exit=0;
}
jsfiddle:
http://jsfiddle.net/dcasadevall/NELWW/

Stuttering orbit animation when updating css through javascript over small interval

I'm trying to make some DOM element rotate smoothly around a fixed point. I'm writing this from scratch using jQuery and no matter what update speed I choose for the setInterval or how small I go with the amount of degrees the orbit advances on each loop, I get this janky staircase animation effect. I've tried using jquery's .animate instead of the .css hoping it would smooth things out but I cant seem to get it to work. Any help is appreciated.
In other words, it's not as smooth as rotating an image in HTML5 canvas. I want to make it smoother.
Here is a jsFiddle demonstrating the issue.
Notice how the animation is not quite smooth?
For reference, here is the code:
HTML
<div id="div"></div>
<div class="dot"></div>
<button class="stop">STOP</button>
<button class="start">START</button>
CSS
#div{
position:absolute;
height: 20px;
width: 20px;
background-color: #000;
}
.dot{
position:absolute;
width: 5px;
height: 5px;
background-color: #000;
}
button{
position:absolute;
}
.stop{
top:200px;
}
.start{
top:225px;
}
THE ALL IMPORTANT JAVASCRIPT
$(document).ready(function(){
$('#div').data('angle', 90);
var interval;
$('.stop').on('click', function(){
if(interval){
clearInterval(interval);
interval = undefined;
}
});
$('.start').on('click', function(){
if(!interval){
interval = setBoxInterval();
}
});
interval = setBoxInterval();
});
function drawOrbitingBox(degrees){
var centerX = 100,
centerY = 100,
div = $('#div'),
orbitRadius = 50;
//dot might not be perfectly centered
$('.dot').css({left:centerX, top:centerY});
//given degrees (in degrees, not radians), return the next x and y coords
function coords(degrees){
return {left:centerX + (orbitRadius * Math.cos((degrees*Math.PI)/180)),
top :centerY - (orbitRadius * Math.sin((degrees*Math.PI)/180))};
}
//increment the angle of the object and return new coords through coords()
function addDegrees(jqObj, degreeIncrement){
var newAngle = jqObj.data('angle') + degreeIncrement;
jqObj.data('angle', newAngle);
return coords(newAngle);
}
//change the left and top css property to simulate movement
// I've tried changing this to .animate() and using the difference
// between current and last position to no avail
div.css(addDegrees(div, degrees), 1);
}
function setBoxInterval(){
var interval = window.setInterval(function(){
drawOrbitingBox(-0.2); //This is the degree increment
}, 10); //This is the amount of time it takes to increment position by the degree increment
return interval;
}
I'd rather not resort to external libraries/plugins but I will if that's the accepted way of doing this kind of stuff. Thank you for your time.
That's because the value you set for top and left properties is rounded up. You should try using CSS Transforms.
Combining CSS Animations/Transitions and CSS Transforms you should also be able to get the animation without JavaScript.
Oh, I run into that myself!
There is actually nothing you can do, the stuttering you see is the pixel size. The pixel is the minimal step for css based animations, you can't do "half pixels" or "0.2 pixels". You will see that the same keeps happening with css3 animations.
The only solution is to speed up your animation, i'm afraid.
Also, cosndsider using rquestAnimationFrame instead of interval: https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame

Need help with animation on JavaScript without jQuery

I have got a div object for example (Simple Image), and I need my picture to move to right and left and backward without any frame and border. My picture will collide with end (right side of my page) and move backward to left and then action with right side too. This will be only on JavaScript.
Edit:
<html>
<head>
<script>
function dvig () {
var xx = 50;
var corner_left=200 +'px';
var corner_right=100 +'px';
var move; var move2;
var dv=document.getElementById("adam");
if(dv.style.left<=corner_right) {
move=1;
move2=1;
}
if(dv.style.left>=corner_left) {
move2=0;
move=0;
}
if(move=1) {
dv.style.left=parseInt(document.getElementById("adam").style.left)+xx;
}
if (move2=0) {
move=0;
dv.style.left=parseInt(document.getElementById("adam").style.left)-xx;
}
}
function chustro() {
setInterval("dvig()", 100);
}
</script>
</head>
<body onload="chustro()">
<img id="adam" style="position: absolute; top: 100px; left: 100px; width: 40px; height: 40px; background-color: red">
</body>
</html>
Your going to have to setup a iterative process that runs every X milliseconds. Each time its run you have to update the div's position a bit and check if it hits a side and reverse direction.
function doWork{
// move current direction a little
// check if past the left edge and change directions
// check if past the right edge and change direction
}
setInterval(doWork, 10);
Update:
Based on your code, check this example:
http://jsfiddle.net/HT9A4/

Categories