Go through a sprite and save background-position - javascript

In the game that I have, when the player walks up to the number and presses the "m" key one frame of the sprite is skipped.
To clarify, the following is my code that I use to keep track of when the frames should change by storing the position of the frames in a variable:
function animateStar() {
var pos = 0;
$(document).keyup(function(e) {
if (e.keyCode == 77) {
pos -= 32;
$('#n1').css('background-position', pos+'px -0px');
}
});
}
So as you can see, everytime the key code 77 (representing "m") is pressed, the frames will change, since each of my frames has a height and width of 32px.
However, the problem that I am having is that when my player walks away from the object and comes back to it, instead of continuing from where he left off, the frames sort of skip.
Here is my code: http://jsfiddle.net/j40s8gjt/
Since my sprite sheet is composed of numbers, you should be able to see what's up with the code.
Try setting the frame at a number between 3-5, walking away from the object then coming back to it and pressing m again, you should see that it sort of re loops everything.
A possible solution of this might be to store the current position of the object when the player leaves it, but I am not sure how to go about doing so.
I hope I've been clear enough, thank you!

Since you're defaulting to 0 each time you call animateStar() it starts over.
Grabbing the current position is what you need to do instead of defaulting to 0 each time.
in animateStar(), Change this line:
var pos = 0;
to this:
var pos = $('#n1').css('background-position').split('px ')[0] || 0;
That way it gets the current position when it starts, instead of starting from 0 again and resetting the frame.
Working example: http://jsfiddle.net/j40s8gjt/2/

Related

Three.js - Spawn an object every x seconds and move each object forward (along Z)

I am making an endless runner style game using Three.js. The basic set up of the scene and idea for the game is a long moving road with cars coming towards you that you have to dodge out of the way of. I am still at the early stages of creating this game, and so my first problem is that I need the hero character (who is dodging the cars) to seem like he is moving forwards, and at the same time have the cars seem like they are moving (faster) towards the hero character.
My thinking was to create road strip objects (the white lines in the middle of a road), and have them move towards the hero character, who is at (0, 0), at a certain speed.
I have successfully created a road strip object and positioned it at the very back of the road (RoadStrip.mesh.position.z = -5000;). Here is my code for that:
var objectRoadStrip = function() {
this.mesh = new THREE.Object3D();
this.mesh.name = "roadStrip";
geomRoadStrip = new THREE.BoxGeometry(20, 11, 300);
matRoadStrip = new THREE.MeshPhongMaterial({color: Colors.white});
RoadStrip = new THREE.Mesh(geomRoadStrip, matRoadStrip);
RoadStrip.name = 'roadStripName';
this.mesh.add(RoadStrip);
}
function createRoadStrip() {
new objectRoadStrip();
RoadStrip.position.y = -72.5;
RoadStrip.position.z = -5000;
scene.add(RoadStrip);
}
In the render() function, which is the function that loops over every frame and is called last to make sure the camera and scene update every frame, I am able to successfully move this strip forwards along the z axis by 10 every time render() is called. I also added some code so that when the RoadStrip touches (0,0), it is removed from the scene. See this below:
function render(){
// moves RoadStrip towards (0,0). When it reaches z = -150, remove that strip from the scene
if (RoadStrip.position.z <= -150) {
RoadStrip.position.z += 10;
} else {
scene.remove(RoadStrip);
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
I have also added the following code to the init() function which creates a RoadStrip when the scene is created, and the continues to create a RoadStrip every 10 seconds (roughly every time the RoadStrip reaches (0,0).
createRoadStrip();
setInterval( function() {
createRoadStrip();
}, 10000);
This is similar to the effect I'm going for, but read The Problem section below where I explain what I truly need.
The Problem
I need to spawn a RoadStrip every x amount of seconds (still to be decided once I get it working, but lets say 3 seconds for now) continuously. Each RoadStrip needs to move towards (0,0) with z += 10 independently. When a RoadStrip instance reaches (0,0), it should be removed from the scene, but other RoadStrips should continue to spawn regardless every 3 seconds at the original position (z = -5000).
My Attempts / Solution Ideas
I've done a lot of reading on this, trawling through code from other people's endless runner games and reading through SO answers but nothing seems to have worked. Below are some of the things I have tried, or some things that I feel would work but I am not doing right/don't have a good understanding of:
Idea: Instead of calling the createRoadStrip() function inside a setInterval, push a RoadStrip object to an array every 3 seconds, and then call that array and move the array along the z axis by += 10.
Possible solution help: I tried changing the setInterval to less than 2 seconds instead of 10 seconds. This caused the RoadStrip to move along the Z axis for 2 seconds as expected, but of course, after 2 seconds another RoadStrip was spawned, and so the first RoadStrip stopped moving along the Z axis, and the new one did instead (for 2 seconds as well) and this process repeated infinitely. This is so close to what I need, but I need each RoadStrip to continue moving, and be remove from the scene when it reaches (0,0)
Thanks for taking the time to read my Question, I look forward to your solutions!
Examples of similar style games: First, Second.
Thanks to #prisoner849 and his link to this thread, I managed to find the solution to the problem, and so I am writing an answer here for anyone who comes across this with the same problem in the future!
I read through the thread and found a link to this JSFiddle, that includes a successful animation similar to the one I was trying to achieve, and I would highly suggest studying the code of that JSFiddle to fully understand how to create an endless runner effect.
Here is a detailed explanation of how to do this:
Instead of infinitely creating objects and have them animate forwards until they reach the end point and disappear (like I originally thought was the right solution), you have to create an array of objects and animate that instead.
Here is my code for doing this:
var roadStripArray = []
function objectRoadStrip() {
for (var i = 0; i < 100; i++) {
geomRoadStrip = new THREE.BoxGeometry(20, 11, 500);
matRoadStrip = new THREE.MeshPhongMaterial({color: Colors.white});
RoadStrip = new THREE.Mesh(geomRoadStrip, matRoadStrip);
RoadStrip.position.set(0, -72.5, -150 - i * 1250);
RoadStrip.receiveShadow = true;
scene.add(RoadStrip);
roadStripArray.push(RoadStrip);
}
}
The for loop has the code i < 100 as my road is quite long and therefore needs a lot of strips
This code:
RoadStrip.position.set(0, -72.5, 0 - i * 1250);
sets the position of each strip to be different from each other, and the number 1250 is the distance between each strip
After creating the objects, you must animate them in the render() function. You have to set them to move along the Z axis, and then create an if statement that says "if any strip reaches the end point (where you want it to disappear), reset it's position back to the start (i.e. the start of the road for me). This means you are constantly looping through your array of objects, and therefore don't infinitely create them.
Here is the code that animates the strips:
// loop that runs every frame to render scene and camera
var clock = new THREE.Clock();
var time = 0;
var delta = 0;
var direction = new THREE.Vector3(0, 0, 1);
var speed = 2000; // units a second - 2 seconds
function render(){
requestAnimationFrame(render);
delta = clock.getDelta();
time += delta;
roadStripArray.forEach(function(RoadStrip){
RoadStrip.position.addScaledVector(direction, speed * delta);
if (RoadStrip.position.z >= 10000) {
RoadStrip.position.z = -10000;
} else {
}
});
renderer.render(scene, camera);
}
The code that moves each strip is:
RoadStrip.position.addScaledVector(direction, speed * delta);
You can read more about .addScaledVector here, but essentially this is the code that animates the strip.
The if statement then checks if the strip touches 10000 (i.e. the end of the road), and if it does, sets the position of that strip to -10000. That strip then moves back towards the end point along the Z axis.
We wrap this all in a forEach function to loop through each RoadStrip in the array and animate them all in the same way. We need to animate them individually so that we can detect when one of them reaches the end of the road.
Thanks, hope this helps!
Usually this kind of scenario is best handled with some kind of particle-system like approach: you don't insert/remove objects continuously to the scene but create a set of objects during initialization, let's say the player can only see 10 road stripes at a time, and your game logic is always moving those 10 stripes, updating positions as needed, once one strip goes out of the field of view, it is recycled at the begining and so on. I don't think you will find a canned solution that does exactly what you are looking for, you would need to come up with the update logic that suits best your game.
I have an example of custom particle system there. Once a particle is getting out of scope, it is made available for the system when it needs to emit a new particle. The number of particle in the pool is always constant and can be defined by the user here just for testing purpose. A similar approach can be used to manipulate your infinite stripes. The repo for that code is available at https://github.com/leefsmp/Particle-System but you can find many other particle system implementations out there, this one is a bit specific to my needs.
Hope that helps.

How do I check my condition on an if statement to see if it is working correctly?

I'm trying to make a type of circular display which cycles through a series of values as well as moving text elements within an svg file. It uses the hammer.js library and uses the drag event. The values can go in either direction. I have it working to some degree. As the last value is shown from an array, it goes back to the beginning of the array to get the first values. Or vice-versa.
var keyArray = ["C","C#","Db","D","D#","Eb","E","F","F#","Gb","G","G#","Ab","A","A#","Bb","B"];
This is my array. Here is how I wrap it past the end of the array and back to the beginning.
** As per the request of a few commenters and the suggested solution by Nina, I have modified the code below to reflect their suggestions. I have also added a few more lines for clarity of what is happening overall.**
var delta = keyArray.length - 5; // can be constant, it is always positive
for(i=0;i<5;i++){
//5 svg text element containing 5 musical keys
keys = document.getElementById("keys"+i);
//ev.deltaX is the change received from the hammer pan event
//text element moves relative to its original starting X
keys.setAttribute("x",startingSpots[i]+ev.deltaX%150);
currentX=keys.getAttribute("x");
currentEdgeIndex=keyArray.indexOf(keys.textContent);
//This if is what appears to be failing.
if (keys.getAttribute("x")>=565){
keys.setAttribute("x",currentX-150);
keys.textContent = keyArray[(currentEdgeIndex + delta) % keyArray.length];
}
}
With the suggested changes, I removed the Number() calls as well as implementing the modulus for the wrapper. The behavior is still erratic. On the example below, if you pan to the right, as the first text element reaches 565, it meets the condition for the if, is moved back to the left by 150.
What it should do next is to change the textContent to the next appropriate value in the array. However, this is where it becomes erratic, it is no longer past 565 so it does not meet the condition of the if statement, but the text changes at every increment of the pan event as if it were.
I am sure I am not seeing something simple that is causing the trouble but not sure what it is.
The array does appear to be circling correctly, though I'm still not sure "How can I check to see if the if statement is being correctly evaluated and met?"
The project can be viewed here. http://codepen.io/cmgdesignstudios/pen/zrmQaE?editors=1010
* Edit with solution *
Nina suggested the problem lie in the handling of the touch event. After further investigation, I found she was correct. I had originally been moving the object relative to its starting position and the deltaX from the touch event. I then was trying to change the current position by simply moving it back to the left rather than adjusting the starting position.
So I replaced the
keys.setAttribute("x",currentX-150);
with
startingSpots[i]-=150;
This kept the movement relative to the starting position and the deltaX of the touch event.
Please delete the Number(...) casting where it's not necessary. ...length returns always number and the result of calculation is a number too.
Your actual key feature is to move 5 entries down, and this can be achieved wit a simple addition and a modulo, to keep the value in a specific range, like
keys.textContent = keyArray[(keyArray.length + currentEdgeIndex - 5) % keyArray.length];
Further simplified can this calculation then lead to just add a positive number of
delta = keyArray.length - 5; // can be constant, it is always positive
keys.textContent = keyArray[(currentEdgeIndex + delta) % keyArray.length];
and make the modulo out of it.

Pacman game - Making a wall block his movement

I'm making a pacman game with Jquery. Pacman's movement is directed by the arrow keys, which triggers a setInterval() that makes him move his width's distance repeatedly, giving the illusion that he is moving Completely straight. Pressing a new key clears the interval and starts him moving somewhere else.
function Player(){
this.left = $('#pacMan').css('left');
/**/
this.top = $('#pacMan').css('top');
/**/
this.rightMove = function(){
if (){
this.left = parseInt(this.left) + 20;
$('#pacMan').animate({'left': this.left}, 100);
}
};
//The object containing the movement method. The empty if statement is the problem I'll get to later.
var timer;
$('body').keydown(function () {
var key = event.which;
window.clearInterval(timer);
timer = window.setInterval(function() {
switch (key) {
case 37:
pacMan.leftMove();
break;
// The keydown function. It's all kind of disjointed, I know.
So the above works fine. My issue however is this: What happens if I put a wall? How would I get him to stop? I am able to do it with one block but not many. Let me explain.
So I have the whole thing laid out on a grid that's the width of pacman. Me appending a div child to one of the grids selects the grid boxes next to it and puts it in an array. My original if statement was that if Pacman's position is shared with the position of the neighboring grid's, one of his movements are disabled.So if he is just left of the block he can't move right, giving the illusion that the block is stopping him from moving.
e.g
If(Pacman.position().left !== gridBox120.position.left(){
pacMan.moveRight()
}
else{
clearInterval()
}
//As long as pacman is not in the spot right next to the block, he can move right.
This works. But what if I want multiple blocks on the stage? How could I get all these things blocks in the if statement? Or would that be the best way to do it?
My plan was to put the neighbouring divs ID in an array and if Pacman's position shares the position of any of the ID's of the items in the array, he can't move right.
I have no idea how to do this. Some sort of iteration? Or maybe an array is not the best idea for this?
If this is not explained properly I'll respond to comments.
Image link. yellow is pacman. purple are the neighbor divs that are sent to arrays
i already did something like this for a brick breaker.
I've tested obj and array for storing blocks. Array is far faster than obj.
My method was : store all the grid in arrays
And verify after each move the left-1, left+1, top-1 and top+1
if (grid[left-1][top] == "block" && move == "left") {
Pacman.stopFunction()
}

Raycasting to make an enemy jump

As stated above, I am trying to build a simple game, but I can't seem to get the enemies moving correctly. The game is a Minecraft style block-based game. The code I am using so far makes the enemy start following me when I get within a certain distance and stop following once I get a certain distance away.
The problem I am having with this script is that the enemy sort of floats off into the distance when I escape him. More importantly, I cannot for the life of me get the enemy to jump. I know that I should be using two Raycasts for this: one to detect a block in front which will make the enemy jump and another to detect below the enemy and let him fall to the level below if there is no collier at his feet? I have no idea how to go about implementing this and some help would be greatly appreciated.
The code I have thus far can be seen below:
var target : Transform; //the enemy's target
var moveSpeed = 3; //move speed
var rotationSpeed = 3; //speed of turning
var range : float=10f;
var range2 : float=10f;
var stop : float=0;
var myTransform : Transform; //current transform data of this enemy
function Awake() {
myTransform = transform; //cache transform data for easy access/preformance
}
function Start() {
target = GameObject.FindWithTag("1Player").transform; //target the player
}
function Update () {
//rotate to look at the player
var distance = Vector3.Distance(myTransform.position, target.position);
if (distance<=range2 && distance>=range) {
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
} else if (distance <= range && distance > stop) {
//move towards the player
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
} else if (distance <= stop) {
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
}
//lock rotation on x and y axis to zero
myTransform.eulerAngles = new Vector3(0f, myTransform.eulerAngles.y, 0);
}
The design can change really a lot. It depends how clever AI do you want ? And how realistic it should be. Firstly you should check distance and as I saw you did that. The question is what if there is a wall or something ? Maybe they are so close to each other but there is a wall between them. This is why you need raycast. So you send a raycast from enemy to player. If there is no obstacle between them AI can decide that "aye I should come after you". But here is another problem for being realistic. What if its not looking to you ? If the AI can spot the player when it looks somewhere else, it is not that cool right ? So you also check if the player is in front of the AI. Maybe we can do it like this :
var heading = target.position - transform.position;
var dot: float = Vector3.Dot(heading, transform.forward);
so if dot is -1 we can say it is directly behind and +1 means in front of it. Well, now another problem. If player should be in front of the AI to be spotted then AI can not stand right ? It should move and turn around randomly. We can work on that later if you gonan need it.
Now another problem what if you hide after an object ? What it should do ? I mean when you are running if something came between you and AI, since raycast will fail it will stop following you right ? What we can do for it ? My sugesstion store the last position of the player which AI saw. And at least go to there to check if AI can find the player there. If it cant, it may keep moving randomly. By doing this it will looks more realistic I believe.
Edit: Lol I realised that i just improved you design and forgot to answer what exactly you asked.
Firstly AI shoudl know if it is grounded or not. What we need to know first distance to ground when we send raycast we gonan need it.
var distanceToGround = GetComponent<Collider>().bounds.extents.y;
function boolean isGrounded(){
return Physics.Raycast(transform.position, -Vector3.up, distanceToGround + 0, 1);
}
AI should send a raycast not from its head more like below the knees. Not send it too far away just a little distance will be enough. It is just to understand it there is an obstacle. And also send another raycast but this time now below the knees. From the jump height. And if it dont hit anything we can decide that there is an obstacle (first raycast says that) but AI can jump over it (second raycast says that). After deciding it, if AI also grounded that means it can jump and pass trough the obstacle.
Lets say this is the part 1. If you want me to keep telling, I can write another part for you. Have a nice day !

Why does my my gravity work in this?

http://davzy.com/gameA/
I can't figure out a smart way to get gravity. Now with this it detects which block the character is over but it does't drop to that block!
Is there a better way to do gravity? I'd like to do this without a game library.
I don't know what you mean by "get gravity"; your question is unclear. I assume that if you can detect when the block is over, you can use the following formula:
s(t) = ut + 1/2at2
Where s is the distance at time t, u is the initial velocity (which in your case would be zero), and a is the acceleration (on Earth this is 9.8m/s2). Essentially you would be adjusting the top position of your object based on the value you get at time t (so original top position of object + s(t)). I would imagine you would use some sort of animation loop. Perhaps a setInterval. Maybe others with more experience in Javascript animation can chime in about the best way to implement this. However, this would be the formula that you would be using to figure out where the object is at time t, if it falls.
Basically gravity in a platformer goes like this:
var currentGrav = 0.0;
var gravAdd = 0.5; // add this every iteration of the game loop to currentGrav
var maxGrav = 4.0; // this caps currentGrav
var charPosY = getCharPosY(); // vertical position of the character, in this case the lower end
var colPosY = getColDow(); // some way to get the vertical position of the next "collision"
for(var i = 0; i < Math.abs(Math.ceil(currentGrav)); i++) { // make sure we have "full pixel" values
if (charPosY == colPosY) {
onGround = true;
break; // we hit the ground
}
onGround = false;
charPosY++;
}
Now to jump one could simply do this:
if (jumpKeyPressed && onGround) {
currentGrav = -5.0; //
}
You can, if you want(and understand C), check out my game for a basic platformer(with moving platforms) here:
http://github.com/BonsaiDen/Norum/blob/master/sources/character.c

Categories

Resources