I've tried asking this question on the Unity answers site, but since I've yet to receive an answer I figured I'd ask this question here as well. I am trying to make a 3D version of the game "Snake", but I am running into serious problems trying to make the first snake segment follow the head of the snake. The GameObjects I am using are spheres with rigidbody components, with the player having control only over the "head" of the snake. Then, as the snake grows, more spheres are added that should follow the path that the main sphere makes.
I would like to know if there is either a more elegant solution to what I am trying to achieve, or at least a little help into what I may do to fix the current implementation. I am attaching the code of the segment that is supposed to follow the head. The naming for the objects are in Spanish, but it may not be that hard to figure out what is going on from a non-Spanish speaking person's perspective.
I have also properly commented the code, so that you can understand what I am doing at each sentence. The main idea that partially works right now is to send the snake segments information about where exactly the head made a turn so that when the segments get to a particular turning point, they can make a turn in the direction the head turned. The problem I have is that sometimes the segment travels past by the point where it should make a turn, and I don't understand if it is because of precision problems (I am making float comparisons to determine if a segment has reached a certain position where it turns) or if it's something else.
using UnityEngine;
using System.Collections.Generic;
using Clases;
public class ControladorSegmento : MonoBehaviour {
//This is a generic list of Objects that store both turning position and turning direction that the head has made
public List<PosicionCambioDireccion> listaPosicionesCambioDireccion;
//This would be the head in the case of only one segment that is following
public GameObject lider;
//Speed
public float rapidez;
//Direction
public Vector3 direccion;
//This is an index that is used to iterate over the list of turning points
private int indiceCambioDireccion;
// Use this for initialization
void Start () {
indiceCambioDireccion = 0;
listaPosicionesCambioDireccion = new List<PosicionCambioDireccion>();
//First find the Head of the snake so that we can access its position in order to determine segment spawning position
lider = GameObject.Find("Cabeza");
//Set the position of the new segment 2 units right behind the head
transform.position = lider.GetComponent<Transform>().position - lider.GetComponent<ControladorCabeza>().direccion * 2f;
//Get the current direction of the head so that the segment inmediately moves in its direction
direccion = lider.GetComponent<ControladorCabeza>().direccion;
}
void LateUpdate () {
//Check if there has been a change in direction that the segment has to follow
if ((listaPosicionesCambioDireccion.Count > 0) && (listaPosicionesCambioDireccion.Count > indiceCambioDireccion)) {
//Compare how close we are to the turning position. If we are sufficiently close, change segment direction
if (Mathf.Abs(transform.position.x - listaPosicionesCambioDireccion[indiceCambioDireccion].posicion.x) < 0.0999999 &&
Mathf.Abs(transform.position.z - listaPosicionesCambioDireccion[indiceCambioDireccion].posicion.z) < 0.0999999) {
//Change segment direction at the current position
direccion = listaPosicionesCambioDireccion[indiceCambioDireccion].direccion;
//Increment turning positions list index so that we get the next turning point in the list (if there is any)
indiceCambioDireccion++;
}
}
}
void FixedUpdate() {
//Change the velocity
GetComponent<Rigidbody>().velocity = direccion * rapidez;
}
}
I am still really new working with Unity and it seems I have still much to learn. And again, if you have a more elegant solution to what I am trying to achieve, please let me know. Right know I am aware that this implementation could cause a sort of memory leak in the sense that, as long as the head keeps changing direction, the list of turning points that is stored is going to keep growing and growing which obviously is something one should avoid.
You may record each segment's position in last frame in a list(include head), at the next frame, create a vector from the current position of the head segment to the last position recorded last frame. Then step the distance of the sum of both head & first segment's radius from the current position of the head, and place your first segment there. Repeat these steps for all other segments consist your snake. Hope this can help you.
Related
My Problem can be seen through this video..
You will be able to see in the link above that until I move rod down every thing works well but as soon as I move down the burger gets stuck in the rod. Help me I want it to just deflect off the surface. Something like ping pong game....
For deflection I used the following snippet of code.
foreach (Bar rod in bar)
{
if(rod.CollisionRectangle.Intersects(GameBall.CollisionRectangle))
{
GameBall.speed *= -1;
Console.WriteLine("game" + GameBall.speed);
}
}
Here gameball refers to the burger and rod refers to the images at the top and the bottom.
What seems to be happening is that the rod is overlapping the ball more than the ball is moving in one frame. In other words, if the ball is moving 3 pixels per frame but the objects are overlapping by 5 pixels they won't be able to come out of collision by simply changing direction. You'll need to actually move the ball out of collision first.
That said, collision detection and response is always tricky code to write. The key is to separate the detection code from the response code.
In other words. For every frame:
Detect all collisions
Move all objects
What you're doing now is moving things during the detection phase. That's going to lead to trouble when 2 objects are moving towards each other.
There's way more material on this subject than I can fit into an answer. I suggest looking around for tutorials on AABB collision detection.
Is your CollisionRectangle the built in Rectangle class in MonoGame/XNA?
Assuming it is and the loop is in Update, maybe you could try inserting a break so that it'll stop updating the gameball speed immediately after the first change. This is because the game is updated 60 times per second, there condition might be true for a few miliseconds or so when the game is updating.
foreach (Bar rod in bar)
{
if(rod.CollisionRectangle.Intersects(GameBall.CollisionRectangle))
{
GameBall.speed *= -1;
Console.WriteLine("game" + GameBall.speed);
break;
}
}
Let me know if it doesn't work and maybe i can try it in a new project when i'm free.
When the ball intersect with the bar, you change the direction but the collision is still here so maybe you can try this:
foreach (Bar rod in bar)
{
if(rod.CollisionRectangle.Intersects(GameBall.CollisionRectangle))
{
GameBall.speed *= -1;
// Reset position of the ball
// Something like :
// For the top bar
Gameball.y = rod.y + rod.height;
// For the bottom bar
// Gameball.y = rod.y - Gameball.height
Console.WriteLine("game" + GameBall.speed);
}
}
Okay so, i have a tiled map (obviously) and implemented a collision detection system which is working really well for me. It has trouble with those pesky corners though. I do know why that is, since i don't even check the corners. And that's the point, i don't know how to do that. So, first of all here is my current code:
Body body = currentObject.Body; // Body is a class storing position, velocity, bounds and so on.
int tileDimensions = level.TileWidth; // Since the tiles are squares...
int leftTile = body.Bounds.Left / tileDimensions;
int topTile = body.Bounds.Top / tileDimensions;
int rightTile = (int)Math.Ceiling((float)body.Bounds.Right / tileDimensions - 1);
int bottomTile = (int)Math.Ceiling(((float)body.Bounds.Bottom / tileDimensions) - 1);
if (body.Velocity.Y > 0) // Moving down.
{
for (int x = leftTile; x <= rightTile; x++)
{
for (int y = bottomTile + 1; y <= (bottomTile + 1) + (body.Velocity.Y / tileDimensions); y++)
{
if (tiles[x, y] != null && !tiles[x, y].IsPassable)
{
newVelocity = new Vector2(body.Velocity.X, MathHelper.Clamp(body.Velocity.Y, 0, tiles[x, y].Body.Bounds.Top - body.Bounds.Bottom));
body.Velocity = newVelocity;
break;
}
}
}
}
So thats just for moving down. There are 3 other constructs like that for up, left and right. The only real difference is the loop and the way i clamp the velocity.
As you can see i just loop through all tiles i could potentially collide with. Then i clamp the velocity, which will slow it down in case there is indeed a tile in it's way.
Now, i'm afraid it's hard to explain my problem with just words, so i'll have to post a picture too.
In this screenshot yellow means unpassable tile, black are the tiles the above code is currently checking for collision and red is the player.
To show you what the problem is, imagine i were to accelerate up and right in this frame. As you can see, there would be a collision with the tile on the upper right of my player but the player will just move into the tile since i don't check it for collision. And i will not check it in the next frame either, since i don't check for blocks i'm in because ... i don't even know, that would betray the whole idea behind my code, wouldn't it ? :P
Of course, i could just extend my "searching" range, but then i would collide with tiles, i shouldn't collide with.
Currently, i'm fixing this with an extra check for all the tiles my bounds are overlapping with and... you know, just moving the player back if i find any. But this is really messy and it doesn't preserve the initial velocity. If the player hits a corner he will move into it, i will detect that, move him back and null his velocity. That just doesn't feel right, it's clunky.
I just can't seem to figure out a good way of dealing with such cases. I doesn't happen too often (since it's really hard to reproduce) but once in a while it happens and that is of course unacceptable.
I'd really like to not even have a bugfix-type thing for it but to integrate it in my other code as nicely as possible. This is not mandatory, but it would be cool to be able to do that.
So i'd really appreciate if anyone of you guys could throw something at me.
Anyway, i hope you were able to follow what i was trying to say. Since english isn't my native language it's a little hard to explain such things at times. Also i'm just really bad at explaining things :/
I suppose you could just add 4 more cases, handing when the currentObject is moving in a diagonal, no?
However, you might want to investigate collision based on bounding volumes.
Sorry if this question is a bit open ended, but I'm pretty new to C# and XNA... and this forum in fact!
I'm creating a game and require a beam of light to emit from a fixed point (bottom left in attached screen capture, belonging to class named PowerStation) and reflect from mirrors which can be moved and rotated by the user. I've added a per-pixel collision detection method, as can be seen working in the attached capture (Mirror turns red).
Currently I've been trying to test for obstacles to the beam's path by creating a Point and moving it along the path of the light until a collision is detected; from there recording the distance travelled and then stretching the Beam sprite in a non-uniform way by the required amount. This is proving difficult already and I think there's still a long way to go with this method.
I was just wondering if anyone has any advice as to the best method to go about detecting obstacles, their rotation, and determining the direction to reflect the Beam (by which side of Mirror is hit), before I fully commit to something that might get really complicated or never even work?
Here is what my Beam class looks like currently... all but one classes inherit from one base class called Object and Objects are all declared in a static objectList belonging to a separate class Items. Apologies if this is bad, messy coding!
class Beam : Object
{
private Vector2 start;
private double length;
private Vector2 POC;
public Beam(Vector2 pos)
: base(pos)
{
spriteName = "beam";
depth = 0.2f;
solid = true;
foreach (Object o in Items.objectList)
{
if (o.GetType() == typeof(PowerStation))
{
start = o.Origin;
}
}
}
public override void Update()
{
Point newPoint = new Point((int)Origin.X, (int)Origin.Y);
while ((!(collision(new Mirror(new Vector2(0, 0))))) && (newPoint.X > 0) && (newPoint.Y > 0)) // && boundaries of window
{
newPoint.Y--; //will be changed to a Vector
}
POC = PointOfCollision(new Mirror(new Vector2(0, 0))); // Need to make it do POC of newPoint, not just the Beam Object!
length = FindLength(start, new Vector2(50, 50));
//Scale = new Vector2( , ); //amount to scale sprite
base.Update();
}
private double FindLength(Vector2 pos1, Vector2 pos2)
{
return (Math.Sqrt(Math.Pow(Math.Abs(pos2.X - pos1.X), 2.0f) + Math.Pow(Math.Abs(pos2.Y - pos1.Y), 2.0f)));
}
}
Any help would be greatly appreciated! Thanks in advance
Forget pixels--since the mirrors apparently can be at any angle you'll certainly have places where you intersect a mirror not on an even pixel. While you could simply count the impact point as the even pixel this will produce a slightly wrong path for the beam.
Instead, take your beam and iterate over all the mirrors, compute the intersection of the beam and the plane of the mirror (handle the case where there is no intersection), then check the intersection to make sure it's within the physical mirror. Record the match that occurs within the shortest distance.
You can almost certainly speed this calculation by figuring bounding boxes for all the mirrors in advance and when checking a beam note what quadrant it's heading towards from the current point--you can reject at least half (and usually 3/4) of all the mirrors with two integer comparisons each.
Repeat until there is either no intersection (the beam escapes) or it hits something that stops it rather than reflects it.
If there are a LOT of mirrors you could take this even farther and chop the screen up into sectors, each of which has a list of mirrors in it. Check only the mirrors in the current sector, if you don't get a hit figure out what sector it enters next and repeat. This is a bit more math casting the ray of the beam in exchange for excluding most of the mirrors without a single instruction. If you are dealing with user-placed mirrors I doubt there would be enough of them to be worth doing it.
Represent everything as vectors: your light beams and the sides of the shapes they bounce upon. Then it's very simple algebra to detect intersections and reflection angles. It'll also be infinitely faster than any pixel-based detection.
I thought I'd be able to find this with some searching on the internet but everything I find is just balls bouncing off walls for something like pong or another arbitrary question. I'm making a 2D dungeon crawler game and when I kill enemies and they drop loot I want the item to come flying out as if it had just been thrown in the air and land a random point on the tile the unit was on.
I've been trying to figure this out myself but I can't figure it out, this is probably asked a lot, I'd be really grateful if someone could help me out.
EDIT AS REQUESTED:
Ok well when a monster would be destroyed I would choose a random location within the tile it's in, let's call this location endLoc and the monster's location startLoc. I would then find the center x point between these two locations and decrease the y by 20 ( because that's how many pixels i want the item to go up by), so let's called this variable launchLoc:
launchLoc = new Vector2(startLoc.X + ((endLoc.X - startLoc.X) / 2), startLoc.Y - 20)
I think that produces the right Vector.
So now I would need to launch the item from startLoc, to launchLoc, then have it come back down to endLoc. This is where it gets confusing and I'm not sure how to make a realistic arc for this. The end result would have the item move like it moved along a gaussian, as if it was thrown into the air.
I tried to make it so during each interval, the velocity is increased by 120th, of the X difference, between the startLoc and launchLoc, by an incrementing multiple, but I couldn't get it to work very well. I'm not sure if this was the best way to do. I use 120th because the y value is 20, and the item moves up 1 pixel every interval, so 1 to 20 added up gives 120, this would make the x movement constantly increase, like it was thrown up.
This is in 2D btw, I hope that helps.
You start with an initial velocity vector at time t0 (v(t0)) and position (p(t0)). Gravity can be assumed to produces a constant acceleration (a(t0) = <0, -9.8 m/s2>, though your value may differ) until the object lands. So the general form of the motion for going from one timeslice to the next is:
p(t) = 0.5*a(0)*(t-t0)2 + v(0)*(t-t0) + p(0)
v(t) = a(0)*(t-t0) + v(0)
To figure out when to stop that motion, you need to figure out at what time the object's path will intersect the surface against which it bounces. You'll have to do this for all of the surfaces for which this can reasonably be expected to happen. So for a plane with line equation Ux + Vy + T = 0 you break the position vector into its components, as in:
p(t) = <px(t), py(t)> Then use the quadratic formula to find tc where p(tc) satisfies the line equation:
0.5*(Uax(t0)+Vay(t0))*tc2 + (Uvx(t0)+Vvy(t0))*tc + (Upx(t0)+Vpy(t0)+T) = 0Chose the branch such that tc > t0. From there it's simple to figure out where the object will collide with the surface. You can then update the velocity vector and position vector based on the behavior of the bounce. If the plane is axially aligned (ie, it's a horizontal plane with normal vector parallel to the Z axis), then just flip the sign of the Z component of the velocity vector and multiply the whole velocity vector by some damping factor d, where 0≤d<1 to damp out the velocity. Then repeat until some predetermined time has passed or the velocity reaches some minimal amount (your call on that).
It becomes a bit more difficult with arbitrarily oriented planes. You will need to calculate the angle of incidence of the collision and reflect the velocity vector about the plane normal. I won't go into the details here, as I suspect you're probably not interested in it.
I'm pretty new to C# and XNA and well programing (like I can follow a tutorial but most of the creating it on my own is still really really hard). Right now I'm going round and round trying to figure out how to do this one "simple" thing.
Here's the idea, its going to be a tower defense game; right now I'm working on bare bone basics. I've got my little sprite guy who will move around with Keyboard input, now I want to click somewhere on the screen and have him "walk" to that point. Only I'm lost on the logic. I can click and he'll jump there with
if (aMouse.LeftButton == ButtonState.Pressed)
{
Position.X = aMouse.X;
Position.Y = aMouse.Y;
}
From what I've read for other mousing input, I'm thinking I'll need some kind of loop (bool maybe?) that will move the sprite in a direction and will have to run a check to see if he's got to that point yet. But getting that point after the mouse click and creating that loop, running the check...I'm clueless.
You need to add some instance variables:
Point2D targetPos;
And some constants:
const Point2D speed;
When you run through your Update() loop, update the current position by adding the speed vector to it (in the correct direction of course) until you are within a predefined threshold from the target position (usually the thresholds are calculated from the speed vector - if the distance from the current position to the target position is less than the length of the speed vector, then you're at your position). Using a bool in this case would work well. When you click your mouse set another instance variable (moving) to true, and once you've reached your target position, set moving to false.
People are answering your question at a very low level. Sometimes it help to think of the problem at a higher level.
What you need is a type of state management. The fancy Computer Science term for that is a Finite State Machine. But don't bother looking that up right now. It's fairly dry and confusing at first :)
Your character currently has one state - "standing around". You need to add and process the "walking to destination" state.
From what I've read for other mousing input, I'm thinking I'll need some kind of loop
You need one loop, called the game loop. If you're using XNA, you've already got one. But you're on the right track.
Every time through the game loop, you should process the current state, and check for what are called State Transitions. That's when you change something in your world from one state to another state. For example, when you click the mouse, you want the guy to start moving.
In your game loop you check to see if a mouse click just happened. If it did, then set up some data (where to move to), and tell him to start walking by setting his state to "walking to destination". Next update, you'll process that state instead.
When your character is in the "walking to desintation" state, you need to update their position, based on the amount of time that passed since the last game update. In XNA, this is calculated for you. If you're not using XNA, then you'll have to check yourself. You might be able to use something like the Stopwatch class, and check the Elapsed field.
If the character is at the destination, you need to switch them back to the "standing around" state.
If you receive another mouse click, it is up to you if you want the "walking to destination" state to pay attention to it or not. If you do pay attention to it, you set up the same sort of data as when you transitioned from the "standing around" state.
So, you'll need these variables:
A timer, to find out the elapsed time since the last game loop (XNA gives it to you)
The current player state (maybe an enum)
The current player position (a vector)
The walking speed of the player (a float, probably), measured in units per second (or millisecond)
Data for the "walking to destination" state - target position (another vector)
Data related to user input (mouse events that occurred since the last update, the position of those clicks, etc)
The character specific data will be different for each character in your game, so you want a new copy of it for each. You'll probably want to put it in a class. The rest of it is more global, so you can keep it separate, or make it part of your game, game loop, input classes, etc (however you choose to organize it).
I won't cover the vector math for how to actually calculate the partial movement stuff, since other people have covered that. No sense in duplicating those answers. It basically boils down to making a vector between your current position and the target position, and multiplying/dividing it by your walking speed (to chop it up to the distance moved in a single update).
I'm assuming you have three things:
Current position
Desired position
Speed to move each 'game tick' // don't know what a game tick is? find out!
You're looking at doing this
// dx, dy are delta x and delta y. It's how far in each direction
// the player must travel
// note, I fixed a typo where they were desired - desired... should be
// desired - current, as they are now
float dx = desiredX - currentX;
float dy = desiredY - currentY;
// d uses the pythagorean theorum to find the distance between current and desired
float d = sqrt(dx*dx + dy*dy);
// fac is how far along that line between desired and current will you move
float fac = d / speed;
// mx is the component of the dx line proportional to the size of fac : d
// which means it's how far in the x direction you'll move
float mx = dx * fac;
float my = dy * fac;
// the new postition is the old position plus the move value
float newPositionX = dx + mx;
float newPositionY = dy + my;
I have found this code to be most useful... additionally I have added an extra couple lines to prevent certain situations from occuring. For instance there will be times where direction is 0.83 and speed may have been modified by game factors like terrain/wheather/etc.... if speed is below 1, the sprite may not move at all or even move in the wrong direction!
if (Vector2.Distance(Position, TargetPosition) > 2.0f)
{
velocity = Vector2.Subtract(TargetPosition, Position);
velocity.Normalize();
/// Now no matter which direction we are going we are always moving # sprite.Speed
/// at velocity or speed below 1 - problems occur where the unit may not move at all!!
if(current_Speed < 1)
{
Vector2 temp = (velocity * 10) * (current_Speed * 10);
Position += temp / 10;
}
else
{
Vector2 temp = velocity * current_Speed;
Position += temp;
}
//convert to int to render sprite to pixel perfect..
Position = new Vector2((int)Position.X, (int)Position.Y);
}