Stop particle effect libgdx - opengl

I have a game that involves lots of collisions and explosions.
Basically, enemy-projectiles are launched from the bottom-right corner of the screen towards the left side. The player can intercept them using his weapon.
I want whenever a "bullet" and a projectile collide, the code will draw pre-made particles at the impact position.
My problem is that in real-time, in collision, the particles are drawn nicely but they never stop. The particles continue to be drawn even after the collision.
Now, I use callback mechanism to inform the renderer a collision took place somewhere, and I pass him the coordinates of the collision(x,y)
Here is my renderer code. I cut some parts from the code, leaving only the relevant ones:
package com.david.gameworld;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.utils.Array;
import com.david.helpers.AssetsLoader;
import com.david.helpers.CollisionAndTouchCallbacks;
public class GameRenderer implements CollisionAndTouchCallbacks.DrawThings{
/* The GameRenderer class. Responsible for all the rendering work and graphics */
public static final float FLOOR_HEIGHT = 100.0f; // Public variable - The floor height
private static final float Pixels_To_Meters = 32.0f; // PTM Ration
public static float screenWidth; // Screen width
public static float screenHeight; // Screen height
public OrthographicCamera camera; // The orthographic camera
private GameWorld world; // The game world object, for rendering
private boolean drawTrajectory;
private boolean drawParticle;
private boolean isDrawnParticle;
private Box2DDebugRenderer debugRenderer; // Debug renderer, to see the positions and sizes of the bodies/fixtures
private SpriteBatch batch; // A sprite batch
private Array<Body> tempBodies; // An array that contains all the bodies of Box2D
private Array<Vector2> collisionPositions;
private float delta;
public GameRenderer(float screenWidth, float screenHeight, GameWorld world) {
this.world = world;
GameRenderer.screenHeight = screenHeight;
GameRenderer.screenWidth = screenWidth;
debugRenderer = new Box2DDebugRenderer();
batch = new SpriteBatch();
camera = new OrthographicCamera();
tempBodies = new Array<Body>();
collisionPositions = new Array<Vector2>();
drawTrajectory = false;
drawParticle = false;
isDrawnParticle = false;
}
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.delta = delta;
// Update the world
world.updateWorld();
batch.setProjectionMatrix(camera.combined);
// Get box2d World bodies
world.getBox2DWorld().getBodies(tempBodies);
// Draw the entire scene
batch.begin();
drawBodiesBox2D();
if(drawTrajectory)
drawTrajectory();
if(drawParticle) {
if(!isDrawnParticle) {
drawParticle();
isDrawnParticle = true;
} else {
if(AssetsLoader.explosion.isComplete()) {
drawParticle = false;
isDrawnParticle = false;
}
}
}
batch.end();
// Debug Renderer for box2d world
}
// If user is aiming, draw the trajectory of the acorn
public void drawTrajectory() {
Gdx.app.log("System Out Println!!!!!!!!!", "Draw projectile");
float t = 0.1f, x = world.getArrayAcorns().peek().getX(), y = world
.getArrayAcorns().peek().getY();
float width = AssetsLoader.orbit.getWidth() / 8 / Pixels_To_Meters;
float height = AssetsLoader.orbit.getHeight() / 8 / Pixels_To_Meters;
float timeSeparation = 0.08f;
for (int i = 0; i < 40; i++) {
x = world.getAcornEquation().getX(t);
y = world.getAcornEquation().getY(t);
batch.draw(AssetsLoader.orbit, x, y, width, height);
t += timeSeparation;
}
}
private void drawBodiesBox2D() {
for (Body body : tempBodies) {
if (body.getUserData() != null
&& body.getUserData() instanceof Sprite) {
Sprite sprite = (Sprite) body.getUserData();
if (!sprite.getTexture().equals(AssetsLoader.ground)) {
sprite.setPosition(body.getPosition().x - sprite.getWidth()
/ 2, body.getPosition().y - sprite.getHeight() / 2);
} else {
sprite.setSize(screenWidth, FLOOR_HEIGHT / Pixels_To_Meters);
}
sprite.setRotation((float) Math.toDegrees(body.getAngle()));
batch.draw(AssetsLoader.catapult_base1, 450 / Pixels_To_Meters,
(FLOOR_HEIGHT - 10) / Pixels_To_Meters,
AssetsLoader.catapult_base1.getWidth()
/ Pixels_To_Meters,
AssetsLoader.catapult_base1.getHeight()
/ Pixels_To_Meters);
sprite.draw(batch);
}
}
}
public void dispose() {
AssetsLoader.dispose();
batch.dispose();
world.dispose();
debugRenderer.dispose();
}
// Update method for the orthographic camera
public void updateCamera(int width, int height) {
camera.setToOrtho(false, width, height);
screenWidth = (float) width;
screenHeight = (float) height;
camera.update();
// Already Meters
}
public OrthographicCamera getCamera() {
return this.camera;
}
private void drawParticle() {
// TODO Auto-generated method stub
AssetsLoader.explosion.setPosition(collisionPositions.first().x,collisionPositions.first().y);
AssetsLoader.explosion.start();
AssetsLoader.explosion.draw(batch,delta);
AssetsLoader.explosion.allowCompletion();
}
#Override
public void signalToTrajectory(boolean flag) {
// TODO Auto-generated method stub
drawTrajectory = flag;
}
#Override
public void signalToParticle(boolean flag, Array<Vector2> positions) {
// TODO Auto-generated method stub
if(flag)
collisionPositions = positions;
drawParticle = flag;
}
}
How can I draw the particle effect once and that's it?

You can use/optimise my particle class, look my post here
To draw the particle effect once and that's it : ( it's in myparticle free method ) :
ParticleEffect effect = new ParticleEffect();
Emitter emitter = effect.getControllers().first().emitter;
if (emitter instanceof RegularEmitter){
RegularEmitter reg = (RegularEmitter) emitter;
reg.setEmissionMode(RegularEmitter.EmissionMode.EnabledUntilCycleEnd);
//reg.durationValue.setLow(10f);
reg.dispose();
}
emitter.dispose();

Related

My kinematic body position and scale are different than the expected position and scale

I'm trying to create a physics system for my "game engine" using Box2D, And when i create a b2_kinematicBody The position is bigger than the expected position and the scale is small than the expected scale.
I tried to change the SetAsBox parameters with SetAsBox(this->transform->scale.x, transform->scale.y) and the same problem
NOTE: For the rendering i'm using SDL2 and the positions are based in the SDL2 positions.
Example of the error
And here is a video of the problem: https://youtu.be/0fMPh8Rk_pY
This is the code of my KinematicBody2D class.
KinematicBody2D.h
class KinematicBody2D : public Component
{
private:
b2BodyDef k_bodydef;
b2Body* k_body;
b2FixtureDef k_fixtureDef;
b2Fixture *k_fixture;
b2World* k_world;
b2PolygonShape polygonShape;
public:
KinematicBody2D();
KinematicBody2D(Scene scene);
void Start() override;
void Loop(float delta) override;
void MovePosition(Vector2 target);
};
KinematicBody2D.cpp (Just the important part)
void KinematicBody2D::Start()
{
this->k_bodydef.type = b2BodyType::b2_kinematicBody;
this->k_bodydef.position = b2Vec2(this->transform->position.x, this->transform->position.y);
this->k_bodydef.angle = Math::Deg2Rad(this->transform->rotation);
this->k_body = this->k_world->CreateBody(&this->k_bodydef);
this->polygonShape.SetAsBox((this->transform->scale.x / 2.0f), (this->transform->scale.y / 2.0f));
this->k_fixtureDef.shape = &this->polygonShape;
this->k_fixture = this->k_body->CreateFixture(&this->k_fixtureDef);
}
void KinematicBody2D::Loop(float delta)
{
this->transform->position.x = this->k_body->GetPosition().x;
this->transform->position.y = this->k_body->GetPosition().y;
this->transform->rotation = Math::Rad2Deg(this->k_body->GetAngle());
this->polygonShape.SetAsBox((this->transform->scale.x / 2.0f), (this->transform->scale.y / 2.0f));
this->transform->scale = Vector2(this->transform->scale.x, this->transform->scale.y);
return;
}
main.cpp (Just the important part)
int main()
{
GameObject playerObj = GameObject("Player");
Scene scene = Scene("Scene", &playerObj);
playerObj.AddComponent<Sprite>("res/Player.png", Vector4(0, 0, 256, 256),
Vector2(64, 64));
playerObj.AddComponent<Rigidbody2D>(scene);
playerObj.AddComponent<Player>(app.GetRawRenderer());
GameObject floor = GameObject("Floor", "Floor");
floor.AddComponent<Sprite>("res/World 1.png");
floor.AddComponent<KinematicBody2D>(scene);
floor.transform.position = Vector2(100, 200);
}

Fix an object to screen in OpenGL

I want to do an FPS camera for a game developed in openGL/glut. I want to see the same part of the gun always. So, I want to fix my gun to the screen, and when my camera changes, my gun changes too. The problem arise when my camera rotates. There is a point where a I lost my gun and I cannot see it. I have one class GunCamera
I have tried to set the gun the same rotation as the camera and almost the same position as it. But it fails when I rotate. I have the class GunCameralike this:
class GunCamera : public Camara
{
Solido *s;
public:
void setSolido(Solido *s) { this->s = s; }
Solido *getSolido() { return s; }
GunCamera(double x = 0, double y = 1.65, double z = 0) :Camara(x, y, z) {}
void update(double dt) {
//Transform to radians
double ry = rot2rad(getRot().getY());
Vector3D vel = { -sin(ry),0,cos(ry) };
setPos(getPos() - vel * dt);
}
void render() {
glRotatef(getRot().getX(), 1, 0, 0);
glRotatef(getRot().getY(), 0, 1, 0);
glRotatef(getRot().getZ(), 0, 0, 1);
glTranslatef(-getPos().getX(), -getPos().getY(), -getPos().getZ());
s->setRot(Vector3D(this->getRot().getX(), -this->getRot().getY(), this->getRot().getZ()));
s->setPos(Vector3D(this->getPos().getX(), this->getPos().getY() - 3.5, this->getPos().getZ() + 5));
}
};
Error appears in render method.

Visual Studio 2017 Exception Unhandled

I'm a novice programmer trying to follow a tuturial on recreating a game on Steam called Timber(I believe). The program was working fine and I had almost completed the tutrial, but I ran into trouble when I added the code:
for (int i = 0 < NUM_BRANCHES; i++;)
{
branches[i].setTexture(textureBranch);
branches[i].setPosition(-2000, -2000);
// Set the sprite's origin to dead center
// We can then spin it around without changing its position
branches[i].setOrigin(220, 20);
}
Visual Studio says: branches[i].setPosition(-2000, -2000); Unhandled exception thrown: write access violation.
this was 0x59AF28. occurred
I'll also post the full code, apologies that it's a bit messy.
#include "stdafx.h"
#include <sstream>
#include <SFML\Graphics.hpp>
using namespace sf;
// Function declaration
void updateBranches(int seed);
const int NUM_BRANCHES = 6;
Sprite branches[NUM_BRANCHES];
// Where is the player/branch?
// Left or right
enum class side{ LEFT, RIGHT, NONE };
side branchPositions[NUM_BRANCHES];
int main()
{
// Creates a video mode object
VideoMode vm(1920, 1080);
// Creates and opens a window for the game
RenderWindow window(vm, "Timber!!!", Style::Fullscreen);
// Create a texture to hold a graphic on the GPU
Texture textureBackground;
// Load a graphic into the texture
textureBackground.loadFromFile("graphics/background.png");
// Create a sprite
Sprite spriteBackground;
// Attach the texture to the sprite
spriteBackground.setTexture(textureBackground);
// Set the spriteBackground to cover the screen
spriteBackground.setPosition(0, 0);
// Make a tree sprite
Texture textureTree;
textureTree.loadFromFile("graphics/tree.png");
Sprite spriteTree;
spriteTree.setTexture(textureTree);
spriteTree.setPosition(810, 0);
// Prepare the bee
Texture textureBee;
textureBee.loadFromFile("graphics/bee.png");
Sprite spriteBee;
spriteBee.setTexture(textureBee);
spriteBee.setPosition(0, 450);
// Is the be currently moving?
bool beeActive = false;
// How fast can the bee fly
float beeSpeed = 0.0f;
// Make 3 cloud sprites from 1 texture
Texture textureCloud;
// Load 1 new texture
textureCloud.loadFromFile("graphics/cloud.png");
// 3 new sprites with the same texture
Sprite spriteCloud1;
Sprite spriteCloud2;
Sprite spriteCloud3;
spriteCloud1.setTexture(textureCloud);
spriteCloud2.setTexture(textureCloud);
spriteCloud3.setTexture(textureCloud);
// Position the clouds off screen
spriteCloud1.setPosition(0, 0);
spriteCloud2.setPosition(0, -150);
spriteCloud3.setPosition(0, -300);
// Are the clouds currently on the screen?
bool cloud1Active = false;
bool cloud2Active = false;
bool cloud3Active = false;
// How fast is each cloud?
float cloud1Speed = 0.1f;
float cloud2Speed = 0.2f;
float cloud3Speed = 0.3f;
// Variables to control time itself
Clock clock;
// Time bar
RectangleShape timeBar;
float timeBarStartWidth = 400;
float timeBarHeight = 80;
timeBar.setSize(Vector2f(timeBarStartWidth, timeBarHeight));
timeBar.setFillColor(Color::Red);
timeBar.setPosition((1920 / 2) - timeBarStartWidth / 2, 980);
Time gameTimeTotal;
float timeRemaining = 6.0f;
float timeBarWidthPerSecond = timeBarStartWidth / timeRemaining;
// Track whether the game is running
bool paused = true;
// Draw some text
int score = 0;
sf::Text messageText;
sf::Text scoreText;
// Font
Font font;
font.loadFromFile("fonts/KOMIKAP_.ttf");
// Set the font of our message
messageText.setFont(font);
scoreText.setFont(font);
// Assign the actual message
messageText.setString("Press Enter to Start!");
scoreText.setString("score = 0");
// Make text really big
messageText.setCharacterSize(75);
scoreText.setCharacterSize(100);
// Choose a color
messageText.setFillColor(Color::White);
scoreText.setFillColor(Color::Black);
// Position the text
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
scoreText.setPosition(20, 20);
// Prepare 6 branches
Texture textureBranch;
textureBranch.loadFromFile("graphics/branch.png");
// Set the texture for each branch sprite
for (int i = 0 < NUM_BRANCHES; i++;)
{
branches[i].setTexture(textureBranch);
branches[i].setPosition(-2000, -2000);
// Set the sprite's origin to dead center
// We can then spin it around without changing its position
branches[i].setOrigin(220, 20);
}
while (window.isOpen())
{
/*
**************
Handles the player input
**************
*/
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
window.close();
}
// Start the game
if (Keyboard::isKeyPressed(Keyboard::Return))
{
paused = false;
// Reset the time and the score
score = 0;
timeRemaining = 5;
}
/*
**************
Update the scene
**************
*/
if (!paused)
{
// Measure time
Time dt = clock.restart();
// Subtract from the amount of time remaining
timeRemaining -= dt.asSeconds();
// size up the time bar
timeBar.setSize(Vector2f(timeBarWidthPerSecond *
timeRemaining, timeBarHeight));
if (timeRemaining <= 0.0f)
{
// Pause the game
paused = true;
// Change the message shown to the player
messageText.setString("Out of time");
// Reposition the text base on its new size
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
}
// Setup the bee
if (!beeActive)
{
// How fast is the bee
srand((int)time(0) * 10);
beeSpeed = (rand() % 400) + 350;
// How high is the bee
srand((int)time(0) * 10);
float height = (rand() % 650) + 850;
spriteBee.setPosition(1921, height);
beeActive = true;
}
else
// Move the bee
{
spriteBee.setPosition(
spriteBee.getPosition().x -
(beeSpeed * dt.asSeconds()),
spriteBee.getPosition().y);
// Has the bee reached the right hand edge of the screen?
if (spriteBee.getPosition().x < -100)
{
// Set it up ready to be a whole new bee next frame
beeActive = false;
}
}
// Manage the clouds
// Cloud 1
if (!cloud1Active)
{
// How fast is the cloud
srand((int)time(0) * 10);
cloud1Speed = (rand() % 150);
// How high is the cloud
srand((int)time(0) * 10);
float height = (rand() % 200);
spriteCloud1.setPosition(-300, height);
cloud1Active = true;
}
else
{
spriteCloud1.setPosition(
spriteCloud1.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud1.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud1.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud1Active = false;
}
}
// Cloud 2
if (!cloud2Active)
{
// How fast is the cloud
srand((int)time(0) * 20);
cloud2Speed = (rand() % 200);
// How high is the cloud
srand((int)time(0) * 20);
float height = (rand() % 300);
spriteCloud2.setPosition(-200, height);
cloud2Active = true;
}
else
{
spriteCloud2.setPosition(
spriteCloud2.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud2.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud2.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud2Active = false;
}
}
// Cloud 3
if (!cloud3Active)
{
// How fast is the cloud
srand((int)time(0) * 30);
cloud3Speed = (rand() % 250);
// How high is the cloud
srand((int)time(0) * 30);
float height = (rand() % 150);
spriteCloud3.setPosition(-100, height);
cloud3Active = true;
}
else
{
spriteCloud3.setPosition(
spriteCloud3.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud3.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud3.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud3Active = false;
}
}
// Update the score text
std::stringstream ss;
ss << "Score = " << score;
scoreText.setString(ss.str());
// Update the branch sprites
for (int i = 0; i < NUM_BRANCHES; i++)
{
float height = i * 150;
if (branchPositions[i] == side::LEFT)
{
// Move the sprite to the left side
branches[i].setPosition(610, height);
// Flip the sprite around the other way
branches[i].setRotation(180);
}
else if (branchPositions[i] == side::RIGHT)
{
// Move the sprite to the right side
branches[i].setPosition(1330, height);
// Set the sprite rotation to normal
branches[i].setRotation(0);
}
else
{
// Hide the branch
branches[i].setPosition(3000, height);
}
}
} // End if(!paused)
/*
**************
Draw the scene
**************
*/
// Clear everything from the last frame
window.clear();
// Draw our game scene here
window.draw(spriteBackground);
// Draw the clouds
window.draw(spriteCloud1);
window.draw(spriteCloud2);
window.draw(spriteCloud3);
// Draw the branches
for (int i = 0; i < NUM_BRANCHES; i++)
{
window.draw(branches[i]);
}
// Draw the tree
window.draw(spriteTree);
// Draw the insect
window.draw(spriteBee);
// Draw the score
window.draw(scoreText);
//Draw the timebar
window.draw(timeBar);
if (paused)
{
// Draw our message
window.draw(messageText);
}
// Show everyting we just drew
window.display();
}
return 0;
}
// Function definition
void updateBranches(int seed)
{
// Move all the branches down on place
for (int j = NUM_BRANCHES - 1; j > 0; j--)
{
branchPositions[j] = branchPositions[j - 1];
}
// Spawn a new branch at postion 0
// LEFt, RIGHT, NONE
srand((int)time(0) + seed);
int r = (rand() % 5);
switch (r)
{
case 0:
branchPositions[0] = side::LEFT;
break;
case 1:
branchPositions[0] = side::RIGHT;
break;
default:
branchPositions[0] = side::NONE;
break;
}
}
setPosition() requires an sf::Vector2f. So you could fix your code by changing that line to:
branches[i].setPosition(sf::Vector2f(-2000, -2000))

Android Studio - Support Multiple Screens

I'm trying to support multiple screen sizes in my app... I added this to my Manifest.xml:
`<supports-screens
android:normalScreens="true"
android:smallScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"/>`
I also added different layout sizes and densities:
layout-small
layout-large
layout-normal
layout-xlarge
drawable-ldpi
drawable-hdpi
drawable-mdpi
drawable-xhpi
My layout-normal is currently set on Nexus 4: Image here
Now it's set on Nexus One: Image here
How can I set the elements to scale automatically?
Is there any other way to scale the elements automatically without setting their height and width to wrap_content or match_parent?
of course you can do it programmatically
example:
I defined Simple Object ImageSize like this:
public class ImageSize {
private float width;
private float height;
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
}
then I created a layout which contains Image(another layout) in it
final LinearLayout sellCarImage = (LinearLayout) findViewById(R.id.sellCarImage);
final RelativeLayout sellCarLayout = (RelativeLayout) findViewById(R.id.sellCarLayout);
then I've calculated width and height to scale view sizes based on image real size:
ImageSize img = new ImageSize();
img = getImageSize(R.drawable.indeximage5, MainActivity.this);
int sellCarWidth = sellCarLayout.getWidth();
int sellCarHeight = (int) ((sellCarWidth * img.getHeight()) / img.getWidth());
and programmatically set width and height:
RelativeLayout.LayoutParams sellCarImageIconParams = new RelativeLayout.LayoutParams(sellCarWidth, sellCarHeight);
//sellCarImageIconParams.setMargins(marg, 0, marg, 0);
sellCarImage.setLayoutParams(sellCarImageIconParams);
sellCarImage.setBackgroundResource(R.drawable.indeximage5);
here is getImageSize
public ImageSize getImageSize(int resource, Context ctx) {
ImageSize imageSize = new ImageSize();
BitmapFactory.Options dimensions = new BitmapFactory.Options();
dimensions.inJustDecodeBounds = true;
Bitmap mBitmap = BitmapFactory.decodeResource(ctx.getResources(), resource, dimensions);
imageSize.setHeight(dimensions.outHeight);
imageSize.setWidth(dimensions.outWidth);
return imageSize;
}
it's better to put them in:
sellCarLayout.post(new Runnable() {
#Override
public void run() {
//here
});
}
I hope it helps

How do I draw lines using XNA?

I've read a bunch of tutorials involving XNA (and it's various versions) and I still am a little confused on drawing primitives. Everything seems to be really convoluted.
Can someone show me, using code, the simplest XNA implementation of drawing one or two lines on to the screen? Perhaps with a brief explanation (including the boilerplate)?
I'm not a games programmer and I have little XNA experience. My ultimate goal is to draw some lines onto the screen which I will eventually transform with rotations, etc (by hand). However, for this first step.. I need to simply draw the lines! I remember back in my ancient OpenGL days it was fairly straightforward when drawing a line with a few method calls. Should I simply revert to using unmanaged directx calls?
When working with XNA, everything (even 2d primitives) have to be expressed in a way that a 3d card can understand, which means that a line is just a set of vertices.
MSDN has a pretty good walkthrough here:
http://msdn.microsoft.com/en-us/library/bb196414.aspx#ID2EEF
You'll find that it takes more code to render a primitive line than it would take to just setup a textured quad and rotate that, since in essence, your doing the same thing when rendering a line.
Following NoHayProblema's answer (I cannot comment yet).
That answer, although the correct one for this old question, is incomplete. Texture2D constructor returns an uninitialized texture, which is never painted on screen.
In order to use that approach, you need to set the texture's data like this:
Texture2D SimpleTexture = new Texture2D(GraphicsDevice, 1, 1, false,
SurfaceFormat.Color);
Int32[] pixel = {0xFFFFFF}; // White. 0xFF is Red, 0xFF0000 is Blue
SimpleTexture.SetData<Int32> (pixel, 0, SimpleTexture.Width * SimpleTexture.Height);
// Paint a 100x1 line starting at 20, 50
this.spriteBatch.Draw(SimpleTexture, new Rectangle(20, 50, 100, 1), Color.Blue);
Take into account that the way you write the data into pixel must be consistent with the texture's SurfaceFormat. The example works because the texture is being formatted as RGB.
Rotations can be applied in spriteBatch.Draw like this:
this.spriteBatch.Draw (SimpleTexture, new Rectangle(0, 0, 100, 1), null,
Color.Blue, -(float)Math.PI/4, new Vector2 (0f, 0f), SpriteEffects.None, 1f);
found a tutorial for that
http://www.bit-101.com/blog/?p=2832
its using a BasicEffect (shader)
and the built in draw user primitive in XNA 4.0
some code samples i find helpful:
load content method
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.Projection = Matrix.CreateOrthographicOffCenter
(0, GraphicsDevice.Viewport.Width,     // left, right
GraphicsDevice.Viewport.Height, 0,    // bottom, top
0, 1);   
draw method
basicEffect.CurrentTechnique.Passes[0].Apply();
var vertices = new VertexPositionColor[4];
vertices[0].Position = new Vector3(100, 100, 0);
vertices[0].Color = Color.Black;
vertices[1].Position = new Vector3(200, 100, 0);
vertices[1].Color = Color.Red;
vertices[2].Position = new Vector3(200, 200, 0);
vertices[2].Color = Color.Black;
vertices[3].Position = new Vector3(100, 200, 0);
vertices[3].Color = Color.Red;
GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, vertices, 0, 2);
have fun and vote up if this helped you. also pay a visit to the tutorial i got this from.
Well, you can do it in a very simple way without getting into the 3D horrible vector stuff.
Just create a quick texture, for example:
Texture2D SimpleTexture = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
And then just draw a line using that texture:
this.spriteBatch.Draw(SimpleTexture, new Rectangle(100, 100, 100, 1), Color.Blue);
I hope this helps
The simplest best way, I think, is to get the image of just a white pixel then stretch that pixel in a rectangle to look like a line
I made a Line class,
class Line
{
Texture pixel = ((set this to a texture of a white pixel with no border));
Vector2 p1, p2; //this will be the position in the center of the line
int length, thickness; //length and thickness of the line, or width and height of rectangle
Rectangle rect; //where the line will be drawn
float rotation; // rotation of the line, with axis at the center of the line
Color color;
//p1 and p2 are the two end points of the line
public Line(Vector2 p1, Vector2 p2, int thickness, Color color)
{
this.p1 = p1;
this.p2 = p2;
this.thickness = thickness;
this.color = color;
}
public void Update(GameTime gameTime)
{
length = (int)Vector2.Distance(p1, p2); //gets distance between the points
rotation = getRotation(p1.X, p1.Y, p2.X, p2.Y); //gets angle between points(method on bottom)
rect = new Rectangle((int)p1.X, (int)p1.Y, length, thickness)
//To change the line just change the positions of p1 and p2
}
public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
spriteBatch.Draw(pixel, rect, null, color, rotation, new Vector2.Zero, SpriteEffects.None, 0.0f);
}
//this returns the angle between two points in radians
private float getRotation(float x, float y, float x2, float y2)
{
float adj = x - x2;
float opp = y - y2;
float tan = opp / adj;
float res = MathHelper.ToDegrees((float)Math.Atan2(opp, adj));
res = (res - 180) % 360;
if (res < 0) { res += 360; }
res = MathHelper.ToRadians(res);
return res;
}
Hope this helps
There is also the "round line" code that "manders" has released on CodePlex:
http://roundline.codeplex.com/
Here is the blog post about it:
XNA RoundLine Code Released on CodePlex
Just stretch a white pixel.
point = game.Content.Load<Texture2D>("ui/point");
public void DrawLine(Vector2 start, Vector2 end, Color color)
{
Vector2 edge = end - start;
float angle = (float)Math.Atan2(edge.Y, edge.X);
spriteBatch.Begin();
spriteBatch.Draw(point,
new Rectangle((int)start.X, (int)start.Y, (int)edge.Length(), 1),
null,
color,
angle,
new Vector2(0, 0),
SpriteEffects.None,
0);
spriteBatch.End();
}
I wanted to draw rays so that I could debug rays created by explosions and where they intersect objects. This will draw a single pixel thin line between two points. This is what I did:
Class to store some simple ray data. The XNA default ray class could work, but it doesn't store the length of the ray to intersection.
public class myRay
{
public Vector3 position, direction;
public float length;
}
A list to store the rays that are to be drawn:
List<myRay> DebugRays= new List<myRay>();
Create a BasicEffect and pass it a "Matrix.CreateOrthographicOffCenter" projection with your desired resolution in the LoadContent method.
Then run this in the draw method:
private void DrawRays()
{
spriteBatch.Begin();
foreach (myRay ray in DebugRays)
{
//An array of 2 vertices - a start and end position
VertexPositionColor[] Vertices = new VertexPositionColor[2];
int[] Indices = new int[2];
//Starting position of the ray
Vertices[0] = new VertexPositionColor()
{
Color = Color.Orange,
Position = ray.position
};
//End point of the ray
Vertices[1] = new VertexPositionColor()
{
Color = Color.Orange,
Position = ray.position + (ray.direction * ray.length)
};
Indices[0] = 0;
Indices[1] = 1;
foreach (EffectPass pass in BasicEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.LineStrip, Vertices, 0, 2, Indices, 0, 1, VertexPositionColorTexture.VertexDeclaration);
}
}
spriteBatch.End();
}
So when an explosion happens in my game it does this (Psuedocode):
OnExplosionHappened()
{
DebugRays.Clear()
myRay ray = new myRay()
{
position = explosion.Position,
direction = GetDirection(explosion, solid),
//Used GetValueOrDefault here to prevent null value errors
length = explosionRay.Intersects(solid.BoundingBox).GetValueOrDefault()
};
DebugRays.Add(ray);
}
It's pretty simple (It possibly looks way more complicated than it is) and it'd be easy to put it into a separate class that you never have to think about again. It also lets you draw a whole lot of lines at once.
I encountered this problem my self and decided to make a class called LineBatch.
LineBatch will draw lines without needing a spriteBatch or dots.
The class is below.
public class LineBatch
{
bool cares_about_begin_without_end;
bool began;
GraphicsDevice GraphicsDevice;
List<VertexPositionColor> verticies = new List<VertexPositionColor>();
BasicEffect effect;
public LineBatch(GraphicsDevice graphics)
{
GraphicsDevice = graphics;
effect = new BasicEffect(GraphicsDevice);
Matrix world = Matrix.Identity;
Matrix view = Matrix.CreateTranslation(-GraphicsDevice.Viewport.Width / 2, -GraphicsDevice.Viewport.Height / 2, 0);
Matrix projection = Matrix.CreateOrthographic(GraphicsDevice.Viewport.Width, -GraphicsDevice.Viewport.Height, -10, 10);
effect.World = world;
effect.View = view;
effect.VertexColorEnabled = true;
effect.Projection = projection;
effect.DiffuseColor = Color.White.ToVector3();
cares_about_begin_without_end = true;
}
public LineBatch(GraphicsDevice graphics, bool cares_about_begin_without_end)
{
this.cares_about_begin_without_end = cares_about_begin_without_end;
GraphicsDevice = graphics;
effect = new BasicEffect(GraphicsDevice);
Matrix world = Matrix.Identity;
Matrix view = Matrix.CreateTranslation(-GraphicsDevice.Viewport.Width / 2, -GraphicsDevice.Viewport.Height / 2, 0);
Matrix projection = Matrix.CreateOrthographic(GraphicsDevice.Viewport.Width, -GraphicsDevice.Viewport.Height, -10, 10);
effect.World = world;
effect.View = view;
effect.VertexColorEnabled = true;
effect.Projection = projection;
effect.DiffuseColor = Color.White.ToVector3();
}
public void DrawAngledLineWithRadians(Vector2 start, float length, float radians, Color color)
{
Vector2 offset = new Vector2(
(float)Math.Sin(radians) * length, //x
-(float)Math.Cos(radians) * length //y
);
Draw(start, start + offset, color);
}
public void DrawOutLineOfRectangle(Rectangle rectangle, Color color)
{
Draw(new Vector2(rectangle.X, rectangle.Y), new Vector2(rectangle.X + rectangle.Width, rectangle.Y), color);
Draw(new Vector2(rectangle.X, rectangle.Y), new Vector2(rectangle.X, rectangle.Y + rectangle.Height), color);
Draw(new Vector2(rectangle.X + rectangle.Width, rectangle.Y), new Vector2(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), color);
Draw(new Vector2(rectangle.X, rectangle.Y + rectangle.Height), new Vector2(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), color);
}
public void DrawOutLineOfTriangle(Vector2 point_1, Vector2 point_2, Vector2 point_3, Color color)
{
Draw(point_1, point_2, color);
Draw(point_1, point_3, color);
Draw(point_2, point_3, color);
}
float GetRadians(float angleDegrees)
{
return angleDegrees * ((float)Math.PI) / 180.0f;
}
public void DrawAngledLine(Vector2 start, float length, float angleDegrees, Color color)
{
DrawAngledLineWithRadians(start, length, GetRadians(angleDegrees), color);
}
public void Draw(Vector2 start, Vector2 end, Color color)
{
verticies.Add(new VertexPositionColor(new Vector3(start, 0f), color));
verticies.Add(new VertexPositionColor(new Vector3(end, 0f), color));
}
public void Draw(Vector3 start, Vector3 end, Color color)
{
verticies.Add(new VertexPositionColor(start, color));
verticies.Add(new VertexPositionColor(end, color));
}
public void End()
{
if (!began)
if (cares_about_begin_without_end)
throw new ArgumentException("Please add begin before end!");
else
Begin();
if (verticies.Count > 0)
{
VertexBuffer vb = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), verticies.Count, BufferUsage.WriteOnly);
vb.SetData<VertexPositionColor>(verticies.ToArray());
GraphicsDevice.SetVertexBuffer(vb);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, verticies.Count / 2);
}
}
began = false;
}
public void Begin()
{
if (began)
if (cares_about_begin_without_end)
throw new ArgumentException("You forgot end.");
else
End();
verticies.Clear();
began = true;
}
}
Here is a simple way that I use to make lines by specifying a start coordinate, an end coordinate, width, and color of them:
NOTE: you must add a file named "dot" to the content directory (the line will be made out of these).
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Xna.LineHelper
{
public class LineManager
{
int loopCounter;
int lineLegnth;
Vector2 lineDirection;
Vector2 _position;
Color dotColor;
Rectangle _rectangle;
List<Texture2D> _dots = new List<Texture2D>();
FunctionsLibrary functions = new FunctionsLibrary();
public void CreateLineFiles(Vector2 startPosition, Vector2 endPosition, int width, Color color, ContentManager content)
{
dotColor = color;
_position.X = startPosition.X;
_position.Y = startPosition.Y;
lineLegnth = functions.Distance((int)startPosition.X, (int)endPosition.X, (int)startPosition.Y, (int)endPosition.Y);
lineDirection = new Vector2((endPosition.X - startPosition.X) / lineLegnth, (endPosition.Y - startPosition.Y) / lineLegnth);
_dots.Clear();
loopCounter = 0;
_rectangle = new Rectangle((int)startPosition.X, (int)startPosition.Y, width, width);
while (loopCounter < lineLegnth)
{
Texture2D dot = content.Load<Texture2D>("dot");
_dots.Add(dot);
loopCounter += 1;
}
}
public void DrawLoadedLine(SpriteBatch sb)
{
foreach (Texture2D dot in _dots)
{
_position.X += lineDirection.X;
_position.Y += lineDirection.Y;
_rectangle.X = (int)_position.X;
_rectangle.Y = (int)_position.Y;
sb.Draw(dot, _rectangle, dotColor);
}
}
}
public class FunctionsLibrary
{
//Random for all methods
Random Rand = new Random();
#region math
public int TriangleArea1(int bottom, int height)
{
int answer = (bottom * height / 2);
return answer;
}
public double TriangleArea2(int A, int B, int C)
{
int s = ((A + B + C) / 2);
double answer = (Math.Sqrt(s * (s - A) * (s - B) * (s - C)));
return answer;
}
public int RectangleArea(int side1, int side2)
{
int answer = (side1 * side2);
return answer;
}
public int SquareArea(int side)
{
int answer = (side * side);
return answer;
}
public double CircleArea(int diameter)
{
double answer = (((diameter / 2) * (diameter / 2)) * Math.PI);
return answer;
}
public int Diference(int A, int B)
{
int distance = Math.Abs(A - B);
return distance;
}
#endregion
#region standardFunctions
public int Distance(int x1, int x2, int y1, int y2)
{
return (int)(Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}
#endregion
}
}