Rotating rectangle with collisions - c

So currently im making a game in raylib library in C
I was expecting to rotate the rectangle but what really did happen the rectangle was being rotated using rectanglepro function but collision werent defined on it so it failed.
im using the following code but it doesnt work
RotatedVector = Vector2Rotate(Vector2Normalize(Center),angle*DEG2RAD);
Where as Vector2Rotate is function of raymath.h defined as:
RMAPI Vector2 Vector2Rotate(Vector2 v, float angle)
{
Vector2 result = { 0 };
float cosres = cosf(angle);
float sinres = sinf(angle);
result.x = v.x*cosres - v.y*sinres;
result.y = v.x*sinres + v.y*cosres;
return result;
}
Vector2Normalize is defined as
RMAPI Vector2 Vector2Normalize(Vector2 v)
{
Vector2 result = { 0 };
float length = sqrtf((v.x*v.x) + (v.y*v.y));
if (length > 0)
{
float ilength = 1.0f/length;
result.x = v.x*ilength;
result.y = v.y*ilength;
}
return result;
}

Related

C Triangle Rasterizer rendering problems

Im trying to write an Software Renderer using this tutorial series: https://www.youtube.com/watch?v=2U-4_vpw1lQ&list=PLEETnX-uPtBUbVOok816vTl1K9vV1GgH5&index=13
But the problem is I try to render a Ico Sphere but it doesn't look right. See image: Rendered Sphere
The code for the rasterizer is:
void GRE_Edge(GTE_Vec4* MinVertY, GTE_Vec4* MaxVertY, GRE_EdgeData* Data)
{
Data->EdgeStartY = (uint32_t)ceilf(MinVertY->y);
Data->EdgeEndY = (uint32_t)ceilf(MaxVertY->y);
Data->EdgeStepX = (MaxVertY->x - MinVertY->x) / (MaxVertY->y - MinVertY->y);
Data->EdgeCurX = MinVertY->x + (Data->EdgeStartY - MinVertY->y) * Data->EdgeStepX;
}
void GRE_ScanEdge(GRE_EdgeData* a, GRE_EdgeData* b, bool Handedness, GRE_Framebuffer* Framebuffer)
{
GRE_EdgeData Left = *a;
GRE_EdgeData Right = *b;
if (Handedness)
{
GRE_EdgeData Temp = Left;
Left = Right;
Right = Temp;
}
for (uint32_t y = b->EdgeStartY; y < b->EdgeEndY; y++)
{
for (uint32_t x = (uint32_t)ceilf(Left.EdgeCurX); x < (uint32_t)ceilf(Right.EdgeCurX); x++)
GRE_DrawPixel(x, y, 255, 0, 255, Framebuffer);
Left.EdgeCurX += Left.EdgeStepX;
Right.EdgeCurX += Right.EdgeStepX;
}
}
void GRE_ScanTriangle(GTE_Vec4* MinVertY, GTE_Vec4* MidVertY, GTE_Vec4* MaxVertY, bool Handedness, GRE_Framebuffer* Framebuffer)
{
GRE_EdgeData TopToBottom;
GRE_Edge(MinVertY, MaxVertY, &TopToBottom);
GRE_EdgeData TopToMiddle;
GRE_Edge(MinVertY, MidVertY, &TopToMiddle);
GRE_EdgeData MiddleToBottom;
GRE_Edge(MidVertY, MaxVertY, &MiddleToBottom);
GRE_ScanEdge(&TopToBottom, &TopToMiddle, Handedness, Framebuffer);
GRE_ScanEdge(&TopToBottom, &MiddleToBottom, Handedness, Framebuffer);
}
float GRE_TriangleAreaTimesTwo(GTE_Vec4* a, GTE_Vec4* b, GTE_Vec4* c)
{
return ((b->x - a->x) * (c->y - a->y) - (c->x - a->x) * (b->y - a->y));
}
void GRE_FillTriangle(GTE_Vec4* v1, GTE_Vec4* v2, GTE_Vec4* v3, GRE_Framebuffer* Framebuffer)
{
GTE_Mat4 ScreenSpaceMatrix;
GTE_Mat4LoadScreenSpaceTransform(&ScreenSpaceMatrix, Framebuffer->Width * 0.5, Framebuffer->Height * 0.5);
GTE_Vec4 MinVertY;
GTE_Vec4MultiplyMat4(v1, &ScreenSpaceMatrix, &MinVertY);
GTE_Vec4PerspectiveDivide(&MinVertY);
GTE_Vec4 MidVertY;
GTE_Vec4MultiplyMat4(v2, &ScreenSpaceMatrix, &MidVertY);
GTE_Vec4PerspectiveDivide(&MidVertY);
GTE_Vec4 MaxVertY;
GTE_Vec4MultiplyMat4(v3, &ScreenSpaceMatrix, &MaxVertY);
GTE_Vec4PerspectiveDivide(&MaxVertY);
//Backface Culling
if (GRE_TriangleAreaTimesTwo(&MinVertY, &MaxVertY, &MidVertY) >= 0)
return;
GTE_Vec4 TmpVec;
if (MaxVertY.y < MidVertY.y)
{
TmpVec = MaxVertY;
MaxVertY = MidVertY;
MidVertY = TmpVec;
}
if (MidVertY.y < MinVertY.y)
{
TmpVec = MidVertY;
MidVertY = MinVertY;
MinVertY = TmpVec;
}
if (MaxVertY.y < MidVertY.y)
{
TmpVec = MaxVertY;
MaxVertY = MidVertY;
MidVertY = TmpVec;
}
GRE_ScanTriangle(&MinVertY, &MidVertY, &MaxVertY, GRE_TriangleAreaTimesTwo(&MinVertY, &MaxVertY, &MidVertY) >= 0, Framebuffer);
}
I can't find any problems with this code, so I hope someone can help me.

Why IsKeyDown always returns true?

I was working in a University C project (first sem), in which our group wanted to make a simple pong game, we decided to use raylib, as it seemed easy. But here is the problem, in the following code:
void UpdatePad(Pad* pad)
{
int height = GetScreenHeight();
if (IsKeyDown(pad->Scheme.DownButton)) {
printf("Down = %d\n", pad->Scheme.DownButton);
pad->Position.y += GetFrameTime() * pad->Speed;
if ( pad->Position.y + pad->Size.y/2 > height ) {
pad->Position.y = height - pad->Size.y /2;
}
}
if (IsKeyDown(pad->Scheme.UpButton)) {
printf("Up = %d\n", pad->Scheme.UpButton);
pad->Position.y -= GetFrameTime() * pad -> Speed;
if (pad->Position.y - pad->Size.y/2 < 0 ) {
pad->Position.y = pad->Size.y /2;
}
}
}
The function IsKeyDown of raylib always returns true, whatever I do. Even if I replace pad->Scheme.DownButton to KEY_UP or something, it always returns true and executes the code block, Is there any solution for this?
Full script is:
#include <raylib.h>
#include <stdio.h>
#include "pad.h"
#include "main.h"
void DrawPad(Pad* pad);
void UpdatePad(Pad* pad);
void Update();
void DrawUpdate();
void Loop();
int main()
{
int screenWidth = 800;
int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "Table Tennis");
SetTargetFPS(12);
Loop();
return 0;
}
void Loop()
{
while (!WindowShouldClose()) {
DrawUpdate();
}
}
void UpdatePad(Pad* pad)
{
int height = GetScreenHeight();
if (IsKeyDown(pad->Scheme.DownButton)) {
printf("Down = %d\n", pad->Scheme.DownButton);
pad->Position.y += GetFrameTime() * pad->Speed;
if ( pad->Position.y + pad->Size.y/2 > height ) {
pad->Position.y = height - pad->Size.y /2;
}
}
if (IsKeyDown(pad->Scheme.UpButton)) {
printf("Up = %d\n", pad->Scheme.UpButton);
pad->Position.y -= GetFrameTime() * pad -> Speed;
if (pad->Position.y - pad->Size.y/2 < 0 ) {
pad->Position.y = pad->Size.y /2;
}
}
}
void DrawPad(Pad* pad)
{
DrawRectangle(pad->Position.x, pad->Position.y - (pad->Size.y /2), pad->Size.x, pad->Size.y, WHITE);
}
void DrawUpdate()
{
const char* scoreLeft = TextFormat("%d", 10);
int scoreSizeLeft = MeasureText(scoreLeft, 20);
InputScheme Input = { .DownButton = KEY_S, .UpButton = KEY_W };
Vector2 paddySize = { .x = 5, .y = 50 };
Vector2 paddyPos = { .x = GetScreenWidth() - paddySize.x , .y = GetScreenHeight() - paddySize.y };
Pad pad = { .Size = paddySize, .Speed = 50, .Scheme = Input , .Position = paddyPos };
Vector2 from = {.x = (GetScreenWidth() / (float) 2), .y = 5};
Vector2 to = { .x = (GetScreenWidth() / (float) 2), .y = ( GetScreenHeight() - (float) 5 ) };
UpdatePad(&pad);
BeginDrawing();
ClearBackground(BLACK);
DrawLineEx(from, to, 2, LIGHTGRAY);
DrawText(scoreLeft, (GetScreenWidth()/2) - 10 -scoreSizeLeft, 10, 20, LIGHTGRAY);
DrawPad(&pad);
EndDrawing();
}
The pad is:-
#include <raylib.h>
typedef struct {
int UpButton;
int DownButton;
} InputScheme;
typedef struct {
InputScheme Scheme;
int Score;
float Speed;
Vector2 Position;
Vector2 Size;
} Pad;

How do I randomise specific colours on Processing

I am looking for some help to randomize specific colors on Processing using the Array functions. For example I only want the colors to be a specifically red, blue, yellow and green. How can I ensure that when each single letter bounces off the wall, the letter's color changes to one of these colors?
Below is my code, really appreciate the help.
String word = "bounce";
char[] letters;
ArrayList<Letter> letterObjects;
boolean ballFall = false;
PFont font;
color randColour = color (0);
Letter l;
void setup () {
size (500, 500);
pixelDensity(displayDensity());
textAlign(CENTER);
textSize(30);
letters = word.toCharArray();
letterObjects = new ArrayList<Letter>();
font = createFont("AvenirNext-Medium", 50);
textFont(font);
//iterate over the letter array
//for each letter create a new object
//add this object to an ArrayLost
for (int i = 0; i<letters.length; i++) {
char currentLetter = letters[i];
float currentPosition = i * 30;
letterObjects.add(new Letter(currentLetter, 180 + currentPosition, height/2));
}
}
void draw () {
background(255);
for (Letter l : letterObjects) {
l.display();
}
if (ballFall == true) {
for (Letter l : letterObjects) {
l.move();
l.bounce();
}
}
}
void mouseClicked() {
ballFall = true;
}
The Letter class
class Letter {
char character;
float x, y;
float xSpeed, ySpeed;
float distance;
Letter(char _c, float _x, float _y) {
character = _c;
x = _x;
y = _y;
//x = random(width);
//y = random(height);
xSpeed = random(1, 3);
ySpeed = random(1, 3);
}
void move () {
x += xSpeed*2;
y += ySpeed*2;
}
void bounce () {
if (x<0 || x>width) {
xSpeed *=-1;
randColour = color (random(255), random (255), random(255));
}
if (y<0 || y>height) {
ySpeed *=-1;
randColour = color (random(255), random (255), random(255));
}
}
void display () {
fill(randColour);
text(character, x, y);
}
}
Make a list of the colors you want to choose from
color red = #FF0000;
color blue = #0000FF;
color yellow = #FFFF00;
color green = #00FF00;
color[] colors = { red, blue, yellow, green };
Then use the random method to pick an index in the array. And use the color at that index:
For your case, you can write your Letter class this way:
Assuming the rest of the code using the Letter class works properly
class Letter {
char character;
float x, y;
float xSpeed, ySpeed;
float distance;
// Declare the colors you want to use in a an array
color red = #FF0000;
color blue = #0000FF;
color yellow = #FFFF00;
color green = #00FF00;
color[] colors = { red, blue, yellow, green };
color randColor;
Letter(char _c, float _x, float _y) {
character = _c;
x = _x;
y = _y;
//x = random(width);
//y = random(height);
xSpeed = random(1, 3);
ySpeed = random(1, 3);
// Pick a random initial color
randColor = colors[int(random(colors.length))];
}
void move () {
x += xSpeed*2;
y += ySpeed*2;
}
void bounce () {
if (x<0 || x>width) {
xSpeed *= -1;
// Pick a random color
randColor = colors[int(random(colors.length))];
} else if (y<0 || y>height) {
ySpeed *= -1;
// Pick a random color
randColor = colors[int(random(colors.length))];
}
}
void display () {
fill(randColor);
text(character, x, y);
}
}

SharpDX Constant/Texture Buffers Don't Work

I've been trying to get the constant/texture buffers to work in SharpDX (it's just like SlimDX), but the data I put in it doesn't seem to get into the shaders.
I've looked up how to do it and followed examples but I just can't get it to work.
Ultimately I will need to be able to input multiple large arrays of various data types into my shaders, so if anyone can give me a working example that can do that, it would be great!
But for now I've written a simple example that I've tried to test, and I just can't get it to work. Usually I can at least get something to display when I draw a triangle but right now it won't even do that.
That's probably a silly mistake I overlooked, but anyway, if someone could just take a look at it and point out what's wrong, or better yet, fix it and post the updated code (it is complete and should compile).
I'm sorry if the code is long but I tried to make it as simple as possible. Anyway, here it is:
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
using SharpDX.D3DCompiler;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test_namespace
{
class Test
{
[StructLayout(LayoutKind.Explicit, Size = 80, Pack = 16)]
public struct Data
{
[FieldOffset(0)]
public Matrix mat;
[FieldOffset(64)]
public Vector4 testColor;
}
[StructLayout(LayoutKind.Explicit)]
public struct Point
{
[FieldOffset(0)]
public Vector4 pos;
[FieldOffset(16)]
public Vector2 tex;
}
int width = 1000;
int height = 1000;
const int vertSize = 6 * sizeof(float);
RenderForm form;
PictureBox pic;
SharpDX.Direct3D11.Device dev;
DeviceContext dc;
SwapChainDescription scd;
SwapChain sc;
RasterizerStateDescription rsd;
RasterizerState rs;
Viewport vp;
Texture2DDescription depthDesc;
DepthStencilView dsv;
RenderTargetView rtv;
SharpDX.Direct3D11.Buffer buffer;
InputLayout il;
VertexShader vs;
ShaderBytecode vsCode;
PixelShader ps;
ShaderBytecode psCode;
Matrix view;
Matrix proj;
Matrix mat;
Data data;
DataStream pointStream;
SharpDX.Direct3D11.Buffer pointBuffer;
public Test()
{
init();
initMat();
data.testColor = new Vector4(1.0f, 0.5f, 0.25f, 0.0f);
string code = "struct vert { float4 pos : POSITION; float2 tex : TEXCOORD; };\n"
+ "struct pix { float4 pos : SV_POSITION; float2 tex : TEXCOORD; };\n"
+ "cbuffer buf1 : register(b0) { float4x4 mat; float4 testColor; }\n"
+ "pix VS(vert vertIn) { pix pixOut = (pix)0; pixOut.pos = mul(vertIn.pos, mat); pixOut.tex = vertIn.tex; return pixOut; }\n"
+ "float4 PS(pix pixIn) : SV_Target { return testColor; }";
vsCode = ShaderBytecode.Compile(code, "VS", "vs_5_0");
vs = new VertexShader(dev, vsCode);
psCode = ShaderBytecode.Compile(code, "PS", "ps_5_0");
ps = new PixelShader(dev, psCode);
dc.VertexShader.Set(vs);
dc.PixelShader.Set(ps);
il = new InputLayout(dev, ShaderSignature.GetInputSignature(vsCode),
new InputElement[] {new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0),
new InputElement("TEXCOORD", 0, Format.R32G32_Float, 16, 0)});
dc.InputAssembler.InputLayout = il;
dc.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
updateBuffer();
RenderLoop.Run(form, () =>
{
dc.ClearDepthStencilView(dsv, DepthStencilClearFlags.Depth, 1.0f, 0);
dc.ClearRenderTargetView(rtv, Color4.Black);
float dist = 10.0f;
draw(new Vector3(-dist, -dist, dist), Vector2.Zero, new Vector3(-dist, dist, dist), Vector2.UnitY,
new Vector3(dist, dist, dist), Vector2.One);
});
}
void init()
{
form = new RenderForm();
form.ClientSize = new System.Drawing.Size(width, height);
form.BackColor = System.Drawing.Color.Black;
form.FormClosed += form_FormClosed;
pic = new PictureBox();
pic.Location = new System.Drawing.Point(0, 0);
pic.Size = new Size(width, height);
pic.Show();
form.Controls.Add(pic);
scd = new SwapChainDescription();
scd.BufferCount = 1;
scd.Flags = SwapChainFlags.AllowModeSwitch;
scd.IsWindowed = true;
scd.ModeDescription = new ModeDescription(width, height, new Rational(60, 1), Format.R8G8B8A8_UNorm);
scd.OutputHandle = pic.Handle;
scd.SampleDescription = new SampleDescription(1, 0);
scd.SwapEffect = SwapEffect.Discard;
scd.Usage = Usage.RenderTargetOutput;
rsd = new RasterizerStateDescription();
rsd.CullMode = CullMode.None;
rsd.DepthBias = 0;
rsd.DepthBiasClamp = 0;
rsd.FillMode = FillMode.Solid;
rsd.IsAntialiasedLineEnabled = true;
rsd.IsDepthClipEnabled = true;
rsd.IsFrontCounterClockwise = false;
rsd.IsMultisampleEnabled = true;
rsd.IsScissorEnabled = false;
rsd.SlopeScaledDepthBias = 0;
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug, scd, out dev, out sc);
rs = new RasterizerState(dev, rsd);
vp = new Viewport(0, 0, width, height, 0.0f, 1.0f);
dc = dev.ImmediateContext;
dc.Rasterizer.State = rs;
dc.Rasterizer.SetViewports(vp);
depthDesc = new Texture2DDescription();
depthDesc.ArraySize = 1;
depthDesc.BindFlags = BindFlags.DepthStencil;
depthDesc.CpuAccessFlags = CpuAccessFlags.None;
depthDesc.Format = Format.D32_Float_S8X24_UInt;
depthDesc.Height = height;
depthDesc.MipLevels = 1;
depthDesc.OptionFlags = ResourceOptionFlags.None;
depthDesc.SampleDescription = new SampleDescription(1, 0);
depthDesc.Usage = ResourceUsage.Default;
depthDesc.Width = width;
dsv = new DepthStencilView(dev, new Texture2D(dev, depthDesc));
rtv = new RenderTargetView(dev, (SharpDX.Direct3D11.Resource)SharpDX.Direct3D11.Resource.FromSwapChain<Texture2D>(sc, 0));
dc.OutputMerger.SetTargets(dsv, rtv);
buffer = new SharpDX.Direct3D11.Buffer(dev, Marshal.SizeOf(typeof(Data)),
ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
dc.VertexShader.SetConstantBuffer(0, buffer);
}
void initMat()
{
view = Matrix.LookAtLH(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)width / (float)height, 0.001f, 10000.0f);
mat = view * proj;
mat.Transpose();
data.mat = mat;
}
void updateBuffer()
{
dc.UpdateSubresource<Data>(ref data, buffer);
}
public void draw(Vector3 p1, Vector2 t1, Vector3 p2, Vector2 t2, Vector3 p3, Vector2 t3)
{
Vector3[] p = new Vector3[3] {p1, p2, p3};
Vector2[] t = new Vector2[3] {t1, t2, t3};
Point[] points = new Point[3];
for(int i = 0; i < 3; i++)
{
points[i] = new Point();
points[i].pos = new Vector4(p[i].X, p[i].Y, p[i].Z, 1.0f);
points[i].tex = new Vector2(t[i].X, t[i].Y);
}
using(pointStream = new DataStream(vertSize * 3, true, true))
{
pointStream.WriteRange<Point>(points);
using(pointBuffer = new SharpDX.Direct3D11.Buffer(dev, pointStream, vertSize * 3,
ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0))
{
dc.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
dc.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(pointBuffer, vertSize, 0));
dc.Draw(3, 0);
}
}
}
void form_FormClosed(object sender, FormClosedEventArgs e)
{
buffer.Dispose();
il.Dispose();
ps.Dispose();
psCode.Dispose();
vs.Dispose();
vsCode.Dispose();
rtv.Dispose();
dsv.Dispose();
dc.ClearState();
dc.Flush();
dc.Dispose();
dev.Dispose();
sc.Dispose();
}
}
}
Also, here is the shader code formatted in a more readable way:
struct vert
{
float4 pos : POSITION;
float2 tex : TEXCOORD;
};
struct pix
{
float4 pos : SV_POSITION;
float2 tex : TEXCOORD;
};
cbuffer buf1 : register(b0)
{
float4x4 mat;
float4 testColor;
}
pix VS(vert vertIn)
{
pix pixOut = (pix)0;
pixOut.pos = mul(vertIn.pos, mat);
pixOut.tex = vertIn.tex;
return out;
}
float4 PS(pix pixIn) : SV_Target
{
return testColor;
}
I'm not sure if this is of any help here, but why go UpdateSubresource in your updateBuffer()? In the SharpDXTutorial/Tutorial16 (the cubemap example) the buffer is initialized with the "device" object,
device.UpdateData<Data>(dataConstantBuffer, sceneInformation);
This is a very handy object. It is contained in SharpHelper, part of SharpDXTutorial,
https://github.com/RobyDX/SharpDX_Demo/blob/master/SharpDXTutorial/SharpHelper/SharpHelper.csproj
.. maybe it takes care of stuff missed, to update the constant buffer?

Box2d elastic rope joint

I'm writing a game, and I need to make up a rope. I maked it by b2RopeJoint, but there I have not found an opportunity to make it elastic.
Then I looked for b2DistanceJoint, everything is cool with the elasticity, but I can't find an ability to set a limit only to the maximum distance (without minimum one).
How can I do it?
Try this.
-(void) CreateElasticRope {
//=======Params
// Position and size
b2Vec2 lastPos = b2Vec2(4,4); //set position first body
float widthBody = 0.35;
float heightBody = 0.1;
// Body params
float density = 0.05;
float restitution = 0.5;
float friction = 0.5;
// Distance joint
float dampingRatio = 0.0;
float frequencyHz = 0;
// Rope joint
float kMaxWidth = 1.1;
// Bodies
int countBodyInChain = 15;
b2Body* prevBody;
//========Create bodies and joints
for (int k = 0; k < countBodyInChain; k++) {
b2BodyDef bodyDef;
if(k==0 ) bodyDef.type = b2_staticBody; //first body is static
else bodyDef.type = b2_dynamicBody;
bodyDef.position = lastPos;
lastPos += b2Vec2(2*widthBody, 0); //modify b2Vect for next body
bodyDef.fixedRotation = YES;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape distBodyBox;
distBodyBox.SetAsBox(widthBody, heightBody);
b2FixtureDef fixDef;
fixDef.density = density;
fixDef.restitution = restitution;
fixDef.friction = friction;
fixDef.shape = &distBodyBox;
body->CreateFixture(&fixDef);
body->SetHealth(9999999);
body->SetLinearDamping(0.0005f);
if(k>0) {
//Create distance joint
b2DistanceJointDef distJDef;
b2Vec2 anchor1 = prevBody->GetWorldCenter();
b2Vec2 anchor2 = body->GetWorldCenter();
distJDef.Initialize(prevBody, body, anchor1, anchor2);
distJDef.collideConnected = false;
distJDef.dampingRatio = dampingRatio;
distJDef.frequencyHz = frequencyHz;
world->CreateJoint(&distJDef);
//Create rope joint
b2RopeJointDef rDef;
rDef.maxLength = (body->GetPosition() - prevBody->GetPosition()).Length() * kMaxWidth;
rDef.localAnchorA = rDef.localAnchorB = b2Vec2_zero;
rDef.bodyA = prevBody;
rDef.bodyB = body;
world->CreateJoint(&rDef);
} //if k>0
prevBody = body;
} //for
}
There's a 2.2 style ropejoint implementation here: https://github.com/aaronfarr/box2Dweb
You can use both a rope joint and a distance joint together. Make the distance of the rope joint a bit longer than the distance joint.
From the Box2D testbed example, I modified the "Web" example as follows:
#ifndef ELASTICROPE_H
#define ELASTICROPE_H
#define NUM_JOINTS 7
#define NUM_LINKS 8
class ElasticRope : public Test
{
public:
ElasticRope()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2CircleShape shape;
shape.m_radius = 0.8f;
// create bodies
for (int b = 0; b < NUM_LINKS; b++) {
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(5.0f, NUM_LINKS-b);
m_bodies[b] = m_world->CreateBody(&bd);
m_bodies[b]->CreateFixture(&shape, 5.0f);
}
for (int j = 0; j < NUM_JOINTS; j++) {
b2DistanceJointDef jd;
b2Vec2 p1, p2, d;
jd.frequencyHz = 5.0f;
jd.dampingRatio = 1.0f;
jd.bodyA = m_bodies[j];
jd.bodyB = m_bodies[j+1];
m_joints[j] = m_world->CreateJoint(&jd);
}
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "This demonstrates an elastic rope.");
m_textLine += DRAW_STRING_NEW_LINE;
}
void JointDestroyed(b2Joint* joint)
{
for (int32 i = 0; i < 8; ++i)
{
if (m_joints[i] == joint)
{
m_joints[i] = NULL;
break;
}
}
}
static Test* Create()
{
return new ElasticRope;
}
b2Body* m_bodies[NUM_LINKS];
b2Joint* m_joints[NUM_JOINTS];
};
#endif // ELASTICROPE_H
Its far from perfect, but may be a starting point.

Resources