XNA 4.0 3D Collision - xna

I've been trying to work on a 3d forward-runner game (like temple run) in XNA 4.0.
I'm hitting a bit of a brick wall, so any help would be much appreciated!
Currently, I'm using my own method for collision detection, which requires the dimensions for each model to be hard-coded into the collision method. I've tried using the code from Microsoft, directly below, but it always returns false:
static bool CheckForCollisions(Entity c1, Entity c2)
{
for (int i = 0; i < c1.body.Meshes.Count; i++)
{
// Check whether the bounding boxes of the two cubes intersect.
BoundingSphere c1BoundingSphere = c1.body.Meshes[i].BoundingSphere;
c1BoundingSphere.Center += c1.position;
for (int j = 0; j < c2.body.Meshes.Count; j++)
{
BoundingSphere c2BoundingSphere = c2.body.Meshes[j].BoundingSphere;
c2BoundingSphere.Center += c2.position;
if (c1BoundingSphere.Intersects(c2BoundingSphere))
{
return true;
}
}
}
return false;
}
This was taken and modified very slightly from, Here My Entity class goes as follows.
Code of mine which I think is relevant would be:
public class Entity
{
public int rowID;
public Model body;
public Vector3 position;
public float rotation = 0f;
public float rotatePerFrame = 0f;
protected internal float toRight = 0;
protected internal float toLeft = 0;
protected internal float forward = 0;
protected internal float back = 0;
protected internal float bottom = 0;
protected internal float top = 0;
public void setDimensions(float right, float left, float front, float back, float top, float bottom)
{
this.toRight = right;
this.toLeft = left;
this.forward = front;
this.back = back;
this.top = top;
this.bottom = bottom;
}
public Entity RotateEnt(Entity e,float degrees)//Psuedo-only accurate to 90 degrees.
{
float actual = MathHelper.ToDegrees(degrees);
switch ((int)actual)
{
case 0:
break;
case 90:
// float temp = e.forward;
// e.forward = e.toLeft;
// e.toLeft =e.back ;
// e.back = e.toRight;
// e.toRight = temp;
float temp = e.forward;
e.forward = e.toRight;
e.toRight = e.back;
e.back = e.toLeft;
e.toLeft = temp;
break;
case 180:
e.forward = e.back;
e.back = e.forward;
e.toRight = e.toLeft;
e.toLeft = e.toRight;
break;
default: //case: 270
e.toRight = e.forward;
e.back = e.toRight;
e.toLeft = e.back;
e.forward = e.toLeft;
break;
}
return e;
}
public bool Collides(Entity e)
{
Entity c1 = RotateEnt(this, this.rotation);
Entity c2 = RotateEnt(e, e.rotation);
float myRightest = c1.position.X + c1.toRight;
float myLeftest = c1.position.X - c1.toLeft;
float hisRightest = c2.position.X + c2.toRight;
float hisLeftest = c2.position.X - c2.toLeft;
if(Collides1D(myLeftest, myRightest, hisLeftest, hisRightest))
{
float myTop = c1.position.Y + c1.top;
float myBottom = c1.position.Y - c1.bottom;
float hisTop = c2.position.Y + c2.top;
float hisBottom = c2.position.Y - c2.bottom;
if (Collides1D(myBottom, myTop, hisBottom, hisTop))
{
float myBack = c1.position.Z - c1.forward;
float myForward = c1.position.Z + c1.back;
float hisBack = c2.position.Z - c2.forward;
float hisForward = c2.position.Z + c2.back;
if (Collides1D(myBack, myForward, hisBack, hisForward))
{
return true;
}
}
}
return false;
}
}
static bool Collides1D(float left1, float right1, float left2, float right2)
{
if (left1 >= left2 && left1 <= right2)
return true;
if (right1 >= left2 && right1 <= right2)
return true;
if (left2 >= left1 && left2 <= right1)
return true;
if (right2 >= left1 && right2 <= right1)
return true;
return false;
}
My own method has been screwing up also, when trying to rotate models.
Ideally, it would be good to know what is wrong with the code from Microsoft, so that I can use it wherever, without worrying about hard-coding in object dimensions.
If anyone can see a fast fix to my own basic collision detection method, that would also be great.
I've looked at the Reimers tutorials, but I'm not getting them at the moment, maybe I've been staring at my own code for too long...
Any other information you want, I can try and supply. I can upload the models also, if that's the problem. I'm using models from Maya, exported as FBX.
I'm using MSVS 2010.
Thanks very much!
Jack

I think the problem may not be in the collision code, but in how you are updating the position of your Entitys. I don't see any update code or MoveForward(), etc, type of code. First of all, though, I think it would be much easier for you to use a Matrix instead of a bunch of float values for rotation. For example, you could have:
public class Entity
{
...
public Matrix RotationMatrix = Matrix.Identity;
public Vector3 position;
Public Entity(Vector3 FaceDirection, Vector3 UpDirection, Vector3 Position)
{
...
position = Position
RotationMatrix = Matrix.CreateWorld(Position, FaceDirection, UpDirection)
}
}
Then if you want to rotate, all you have to do is:
public Void RotateEnt(float Degrees)
{
RotationMatrix *= Matrix.CreateFromAxisAngle(RotationMatrix.Up, MathHelper.ToRadians(Degrees));
}
And if you do all this, then you should easily be able to update your Entity's position, which I think is the problem
public Void Update(GameTime gametime)
{
position += RotationMatrix.Forward * gametime.ElapsedRealTime.TotalMilliseconds * x; //x = some number to scale up or down velocity.
}
If you do this, I think your Entity's position will be updated, which then should fix your collision problem. But, not knowing how you update the position of your Entities, I am just speculating. HTH

Related

How to take damage from enemies (bullets)

Hello fellow programmers! I am sorry to bother you, but I have a school project which is to create a game. I am almost finish all I have to do is to make my character (player) take damage from the enemy bullets.
Here is my enemy class where I have my bullet list which makes the enemies shoot bullets. You can see that Ive tried to track the position of the bullets by temp.(I followed these tutorials on making the enemies https://www.youtube.com/watch?v=_TlnUM-uhSI and https://www.youtube.com/watch?v=tfiKwOo_4xo)
Before you jump on me I just wanna say I have searched everywhere for an answer but since XNA is very limited on what I wanna create it makes it very hard for me.
class Enemies
{
public Texture2D texture;
public Vector2 position;
public Vector2 velocity;
public bool isVisible = true;
Random random = new Random();
int randX, randY;
float temp_bulletenemyX;
float temp_bulletenemyY;
// bullets
private List<Bullets> bullets = new List<Bullets>();
Texture2D bulletTexture;
public Enemies(Texture2D NewTexture, Vector2 NewPosition, Texture2D newBulletTexture)
{
texture = NewTexture;
position = NewPosition;
randY = random.Next(-4, 4);
randX = random.Next(-4, -1);
velocity = new Vector2(randX, randY);
bulletTexture = newBulletTexture;
}
float shoot = 0;
public void update(GraphicsDevice graphics, GameTime gameTime)
{
KeyboardState keyboardState = Keyboard.GetState();
position += velocity;
if (position.Y <= 0 || position.Y >= graphics.Viewport.Height - texture.Height)
velocity.Y = -velocity.Y;
if (position.X < 0 - texture.Width)
isVisible = false;
shoot += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (shoot > 1)
{
shoot = 0;
Shootbullet();
}
updateBullets();
}
public void updateBullets()
{
foreach (Bullets bullet in bullets)
{
bullet.position += bullet.velocity;
temp_bulletenemyX = bullet.position.X;
temp_bulletenemyY = bullet.position.Y;
if (bullet.position.X < 0)
bullet.isVisible = false;
}
for (int i = 0; i < bullets.Count; i++)
if(!bullets[i].isVisible)
{
bullets.RemoveAt(i);
i--;
}
}
public void Shootbullet()
{
Bullets newBullet = new Bullets(bulletTexture);
newBullet.velocity.X = velocity.X - 3f;
newBullet.position = new Vector2(position.X + newBullet.velocity.X, position.Y + (texture.Height / 2) - (bulletTexture.Height / 2));
newBullet.isVisible = true;
if (bullets.Count() < 3) // hur många skott den skall skjuta
bullets.Add(newBullet);
}
public void draw(SpriteBatch spriteBatch)
{
foreach (Bullets bullet in bullets)
bullet.Draw(spriteBatch);
spriteBatch.Draw(texture, position, Color.White);
}
public float PosX
{
get
{
return position.X;
}
}
public Vector2 Pos
{
get
{
return position;
}
}
public float PosY
{
get
{
return position.Y;
}
}
public List<Bullets> GetbulletList
{
get{
return bullets;
}
}
public Texture2D text
{
get
{
return texture;
}
}
public Texture2D BulletText
{
get
{
return bulletTexture;
}
heres the fundamental Game1 code which I have tried to make so my character can take damage.
player.rectangle = new Rectangle(Convert.ToInt32(player.PosX), Convert.ToInt32(player.PosY), player.text.Width, player.text.Height);
foreach (Enemies bullet in enemies.ToList())
{
rec_bullet = new Rectangle(Convert.ToInt32(bullet.GetbulletList.ElementAt(i).position.X), Convert.ToInt32(bullet.GetbulletList.ElementAt(i).position.Y), nyenemy.BulletText.Width, nyenemy.BulletText.Height);
hit = CheckCollision(rec_bullet, player.rectangle);
if (hit == true)
{
player.health -= 10;
hit = false;
}
i++;
I am very sorry if everything is a mess, Ive have put everything together through following many tutorials and some of my own coding. I am also very sorry if I am violating forum rules, I am new here.
Best Regards Kiar.
I'm going to be brave and suggest the following - looking at the snippets of code supplied.
In Game1 code - you are working you way through the enemies, however it looks like you are not searching through the list of bullets for each enemy. You are getting the ElementAt(..) with 'i' - adding one to it, then going to the next enemy and then only getting the ElementAt(..) with the incremented 'i'.
From my understanding - the flow of the code should be:
for each enemy in enemy list
for each bullet in enemy bullet list
Check Collision with Player
if collision then adjust player health
There are a few things wrong with your code. For starters, your Bullet class should contain the bulletUpdate() method, which should be called in a foreach loop.
foreach (Bullet b in bullets)
{
b.update(/*parameters here*/);
}
Your bullets List should be a public list stored in your Game1.cs or an EnemyManager class, not in each enemy. Pass each enemy a reference to that list, so that when they fire, they can add the bullet to the list.
On top of that, your collision test should be nothing more than an Intersection test between each bullet and yourself. Again, another foreach loop.
foreach(Bullet b in bullets)
{
//where playerRect is the hitbox for your player and b.Rect is the hitbox for your bullet
if(playerRect.Intersects(b.Rect)
player.healh-=damage;
}
Hope that helps.

Dart StageXL activate mouse event on overlapping sprites

Is it possible to have a mouse event be called for two sprites overlapping? I have attempted to use getObjectsUnderPoint however it does not seem to be working.
class Line extends Sprite
{
int x;
int y;
int type;
var tempLine = new Shape();
bool isClicked = false;
Line(int xPos, int yPos, int type)
{
this.x = xPos;
this.y = yPos;
this.type = type;
if(type == 1)
{
graphics.beginPath();
graphics.moveTo(x, y);
graphics.lineTo(x+300, y);
graphics.closePath();
graphics.strokeColor(Color.LightGray,19);
addEventListener(MouseEvent.CLICK, react);
tempLine.graphics.beginPath();
tempLine.moveTo(x,y);
tempLine.graphics.lineTo(x+300,y);
tempLine.graphics.closePath();
}
else if(type == 2)
{
graphics.beginPath();
graphics.moveTo(x, y);
graphics.lineTo(x, y+300);
graphics.closePath();
graphics.strokeColor(Color.LightGray,19);
addEventListener(MouseEvent.CLICK, react);
tempLine.graphics.beginPath();
tempLine.moveTo(x,y);
tempLine.graphics.lineTo(x,y+300);
tempLine.graphics.closePath();
}
addChild(tempLine);
}
react(MouseEvent event)
{
Point tempPoint = new Point(event.localX, event.localY);
graphics.strokeColor(Color.Black,19);
isClicked = true;
var subShape = getObjectsUnderPoint(tempPoint);
for(Shape i in subShape)
{
i.parent.userData.isClicked = true;
}
}
}
I have two Line objects overlapping and when one is clicked I want the boolean for both objects to be true. I have read that the getObjectsUnderPoint does not return a Sprite, could this be the issue?
MouseEvents are only dispatched to the top most display object that extends the InteractiveObject class (which is true for all DisplayObjectContainers and Sprites). So only one display object can receive the MouseEvent.CLICK event. You are right that the getObjectsUnderPoint does only return the children of DisplayObjectContainers but there is an open issue on the GitHub repository (https://github.com/bp74/StageXL/issues/209) talking about this. One of the next versions of StageXL (greater than version 0.13) may change this behavior.

Print Canvas from Processing

I am trying to make something along the lines of this: http://instaprint.me/, however I don't have a dedicated Linux machine, ink-less paper and WiFi. I do, on the other hand, have a desktop connected to the internet and a color photo-printer.
So what I had in mind was this -
Set up an Instagram API App that gets all the information of the most recent photo
A PHP script and a server that can produce a static URL for the most recent photo with a header("Content-Type: image/jpeg"), so that every time I take a new photo, the contents of the image on that static page changes to be the most recent photo.
Other pages, like the one mentioned above, that change to reflect the new location and caption of each photo I take, hosted on a static URL.
Some basic knowledge of Processing.
So here's how for I've got so far - I can download the most recent photo ID, and if it has changed since the last time it checked (15 seconds ago), then it proceeds to download the most recent image, caption and location.
I can then arrange these on the canvas to look like an old-fashioned polaroid. Now the only thing I have to do is print the canvas, at 150dpi, on a piece of 6x4in photo paper.
Anyone got any idea how I could do this?
Focusing on the part about bringing up large images in Processing, I did a Google search and came up with this thread. Quoting their problem and results:
The goal is to print a 180 pdi image with a shape depending on the
original canvas. So can be diffrent but it will end up being a
1500x1000mm picture approximately. So a big image. I'm not trying to
display it just to dump it into a file.
Then I setup a 64bits JVM. The latest one from Oracle website. Then I
created different size of picture and push the memory up to 1024MB. 5000x7500 test OK and 6000x9000 test OK
I tried to setup the memory up to 1500MB, but the JVM was not able to start.
So I tried 1200MB 8000x12000 test OK
So it doesn't do the image-printing part but it brings up key information on getting large images in memory via a Java Virtual Machine (JVM).
Lastly, this thread describes a TileSaver class for viewing/printing a large number of pixels using OpenGL. I pasted a large code block below. (This may be unrelated to your question but makes the answer more complete for other uses.)
import processing.opengl.*;
import toxi.geom.*;
Tiler tiler;
void setup() {
size(640,480,OPENGL);
tiler=new Tiler((PGraphics3D)g,NUM_TILES);
}
void draw() {
// see thread
}
/**
* Implements a screen tile exporter with support for FOV,
* clip planes and flexible file formats.
*
* Re-engineered from an older version by Marius Watz:
* http://workshop.evolutionzone.com/unlekkerlib/
*
* #author toxi <info at postspectacular dot com>
*/
class Tiler {
protected PGraphics3D gfx;
protected PImage buffer;
protected Vec2D[] tileOffsets;
protected double top;
protected double bottom;
protected double left;
protected double right;
protected Vec2D tileSize;
protected int numTiles;
protected int tileID;
protected float subTileID;
protected boolean isTiling;
protected String fileName;
protected String format;
protected double cameraFOV;
protected double cameraFar;
protected double cameraNear;
public Tiler(PGraphics3D g, int n) {
gfx = g;
numTiles = n;
}
public void chooseTile(int id) {
Vec2D o = tileOffsets[id];
gfx.frustum(o.x, o.x + tileSize.x, o.y, o.y + tileSize.y,
(float) cameraNear, (float) cameraFar);
}
public void initTiles(float fov, float near, float far) {
tileOffsets = new Vec2D[numTiles * numTiles];
double aspect = (double) gfx.width / gfx.height;
cameraFOV = fov;
cameraNear = near;
cameraFar = far;
top = Math.tan(cameraFOV * 0.5) * cameraNear;
bottom = -top;
left = aspect * bottom;
right = aspect * top;
int idx = 0;
tileSize = new Vec2D((float) (2 * right / numTiles), (float) (2 * top / numTiles));
double y = top - tileSize.y;
while (idx < tileOffsets.length) {
double x = left;
for (int xi = 0; xi < numTiles; xi++) {
tileOffsets[idx++] = new Vec2D((float) x, (float) y);
x += tileSize.x;
}
y -= tileSize.y;
}
}
public void post() {
if (isTiling) {
subTileID += 0.5;
if (subTileID > 1) {
int x = tileID % numTiles;
int y = tileID / numTiles;
gfx.loadPixels();
buffer.set(x * gfx.width, y * gfx.height, gfx);
if (tileID == tileOffsets.length - 1) {
buffer.save(fileName + "_" + buffer.width + "x"
+ buffer.height + "." + format);
buffer = null;
}
subTileID = 0;
isTiling = (++tileID < tileOffsets.length);
}
}
}
public void pre() {
if (isTiling) {
chooseTile(tileID);
}
}
public void save(String path, String baseName, String format) {
(new File(path)).mkdirs();
this.fileName = path + "/" + baseName;
this.format = format;
buffer = new PImage(gfx.width * numTiles, gfx.height * numTiles);
tileID = 0;
subTileID = 0;
isTiling = true;
}
public boolean isTiling() {
return isTiling;
}
}

is it possible to move the map on touch in blackberry by using MapField.

I am using mapField to create a custom map.I am using the code in this link.
How to show more than one location in Blackberry MapField?.
But the map position is fixed. i am not able to drag the map as we can do in google maps or when we invoke the maps like
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments());
}
Here's some code that should get you going on the correct path. I've taken it from a project of mine that had some special requirements, so there could be some remnants of that left in there inadvertently. There will be some undefined variables in there -- they're member variables that are declared in the class and should all start with an underscore. This is also part of a class that extends MapField, so you would have to create a custom map class and then use that rather than the default.
protected boolean touchEvent(TouchEvent message) {
boolean ret = super.touchEvent(message);
//mark that we're starting to interact
if(message.getEvent() == TouchEvent.DOWN) {
_startTouchTracking = true;
_clicking = true;
_touchX = message.getX(1);
_touchY = message.getY(1);
}
//user is wanting to move the map
else if(message.getEvent() == TouchEvent.MOVE) {
int dx = _touchX - message.getX(1);
int dy = _touchY - message.getY(1);
_clicking = false;
_touchX = message.getX(1);
_touchY = message.getY(1);
//perform checks to make sure we don't move outside of the map's range
int lat = getLatitude() - dy*(int)MathUtilities.pow(2, (double)getZoom());
if(lat < -9000000) {
lat = -9000000;
}
else if (lat > 9000000) {
lat = 9000000;
}
int lon = getLongitude() + dx*(int)MathUtilities.pow(2, (double)getZoom());
if(lon < -18000000) {
lon = -18000000;
}
else if (lon > 18000000) {
lon = 18000000;
}
moveTo(lat, lon);
}
//if the person just touches and releases, we want to move to that spot
else if (message.getEvent() == TouchEvent.UNCLICK && _clicking) {
int dx = message.getX(1) - getWidth()/2;
int dy = message.getY(1) - getHeight()/2;
move(dx, dy);
_clicking = false;
}
//touch has been released
else if (message.getEvent() == TouchEvent.UP) {
_startTouchTracking = false;
}
//we handled the click
return true;
}
As said, this might need tweaking for your use, but in general should get you started. The MathUtilities.pow() calls were my way of coming up with an appropriate amount of motion depending on the zoom level.
Edit for Comments
Letting a Bitmap move with the map:
protected Coordinates _bitmapCoordinates;
protected Bitmap _bitmap;
public YourMapField() {
//we're going to put the bitmap at -38.43, 20.32
_bitmapCoordinates = new Coordinates(-38.43, 20.32, 0.0);
_bitmap = YOUR_CODE_TO_GET_THE_BITMAP;
}
protected void paint(Graphics g) {
super.paint(g);
XYPoint placeToPaintBitmap = new XYPoint();
convertWorldToField(_bitmapCoordinates, placeToPaintBitmap);
//perform a check here to make sure that field will be seen. This code would depend
//on how you're painting the image. Just check the placeToPaintBitmap.x and placeToPaintBitmap.y
//against 0 and the map's width and height, along with some adjustment for how you paint
if(bitmap will be visible on the screen) {
//The code I have here is drawing the bitmap from the top left of the image, but if
//you need to draw from some other place you may have to offset the x and y
g.drawBitmap(placeToPaintBitmap.x, placeToPaintBitmap.y, _bitmap.getWidth(), _bitmap.getHeight(), 0, 0);
}
}
I didn't test any of that code, so it might be buggy but should give you the general idea.

Low pass filter software?

I'm looking for digital low pass filter code/library/class for a .net windows forms project, preferably written in c, c++ or c#. I probably need to set the number of poles, coefficients, windowing, that sort of thing. I can't use any of the gpl'd code that's available, and don't know what else is out there. Any suggestions appreciated.
Here is a Butterworth Low Pass filter I wrote for a recent project.
It has some magic numbers as constants that was given to me. If you can figure out how to create the magic numbers with your poles, coefficients, etc, then this might be helpful.
using System;
using System.Collections.Generic;
using System.Text;
namespace Filter
{
public class ButterworthLowPassFilter
{
//filter fc = 2hz, fs = 10hz
private const int LowPassOrder = 4;
private double[] inputValueModifier;
private double[] outputValueModifier;
private double[] inputValue;
private double[] outputValue;
private int valuePosition;
public ButterworthLowPassFilter()
{
inputValueModifier = new double[LowPassOrder];
inputValueModifier[0] = 0.098531160923927;
inputValueModifier[1] = 0.295593482771781;
inputValueModifier[2] = 0.295593482771781;
inputValueModifier[3] = 0.098531160923927;
outputValueModifier = new double[LowPassOrder];
outputValueModifier[0] = 1.0;
outputValueModifier[1] = -0.577240524806303;
outputValueModifier[2] = 0.421787048689562;
outputValueModifier[3] = -0.0562972364918427;
}
public double Filter(double inputValue)
{
if (this.inputValue == null && this.outputValue == null)
{
this.inputValue = new double[LowPassOrder];
this.outputValue = new double[LowPassOrder];
valuePosition = -1;
for (int i=0; i < LowPassOrder; i++)
{
this.inputValue[i] = inputValue;
this.outputValue[i] = inputValue;
}
return inputValue;
}
else if (this.inputValue != null && this.outputValue != null)
{
valuePosition = IncrementLowOrderPosition(valuePosition);
this.inputValue[valuePosition] = inputValue;
this.outputValue[valuePosition] = 0;
int j = valuePosition;
for (int i = 0; i < LowPassOrder; i++)
{
this.outputValue[valuePosition] += inputValueModifier[i] * this.inputValue[j] -
outputValueModifier[i] * this.outputValue[j];
j = DecrementLowOrderPosition(j);
}
return this.outputValue[valuePosition];
}
else
{
throw new Exception("Both inputValue and outputValue should either be null or not null. This should never be thrown.");
}
}
private int DecrementLowOrderPosition(int j)
{
if (--j < 0)
{
j += LowPassOrder;
}
return j;
}
private int IncrementLowOrderPosition(int position)
{
return ((position + 1) % LowPassOrder);
}
}
}
Keith
Ok, I found out how to get the coefficients you used. I downloaded Octave for windows and ran the butter command (as in MatLab) like this:
[b,a] = butter(3, .4, 'low')
Now I can use this code with other fs and fc parameters.

Resources