PDA

View Full Version : کمک در مورد حرکت پرتابه



me.enik
سه شنبه 10 مرداد 1391, 15:56 عصر
سلام.
من داشتم یه برنامه حرکت پرتابه مینوشتم.
به یه جاهایی هم رسید, فقط میخواستم وقتی که مثلا به سطح زمین برخورد کرد, اون وقت, حرکت عکس انجام بده و به سمت بالا حرکت کنه.
فکر کنم واضح باشه که چی میخوام, میخوام یه چیزی مثل توپ باشه که وقتی خوردش به زمین, دوباره به بالا برگرده و دوباره بیاد پایین و ... !

این سورس کدی که من نوشتم :

procedure TForm1.Button1Click(Sender: TObject);
var
deltax,vx,vy,a,y,x,deltavy,deltay : real;
zarbey , zarbex : boolean;
i : integer;
begin

zarbey:= false;
x:=100;
y:=100;
vx:=strtofloat(edit1.Text);
vy:=StrTofloat(edit2.Text);
form1.Canvas.Ellipse(round(x),round(y),round(x)+30 ,round(y)+30);
a:=10;
for I := 1 to 7000 do
begin
sleep(5);
form1.Canvas.Pen.Color:= clbtnface;
Form1.Canvas.Ellipse(round(x),round(y),round(x)+30 ,round(y)+30);

deltavy:=a*Timer1.Interval/19000;

vy:=vy+deltavy;
deltax:=vx*Timer1.Interval/19000;
deltay:=vy*Timer1.Interval/19000;

if (y >= 900) then zarbey := true;
if (zarbey = false) then y:=y+deltay;


if ( zarbey = true ) then
begin
y:=y-deltay;
end;

x:=x+deltax;

form1.Canvas.Pen.Color:= clblack;
Form1.Canvas.Ellipse(round(x),round(y),round(x)+30 ,round(y)+30);

end;

میدونم اشکال از کجاست, ولی نمیتونم درستش کنم.
الآن وقتی میخوره زمین, هوا میره (!!), و دیگه بر نمیگرده.

یه کمکی بکنید, ممنون میشوم.

Ananas
سه شنبه 10 مرداد 1391, 21:51 عصر
سلام.
خیلی جالبه. ببینید شما یک تابع باید داشته باشی که وقتی از محل خاصی با سرعت اولیه توپ پرتاب شد حرکت کنه تا بخوره به زمین، که این مرحله رو نوشتی ولی نه تو یک تابع مستقل. حالا مرحله ی بعد وقتی که توپ به زمین می خوره باید تابع کارش تموم بشه و یک خروجی به شکل مکان برخورد و سرعت اولیه که همون بازتاب سرعت هنگام برخورد به زمینه هست رو برگردونه. یعنی این 4 تا عدد مکان x, y و سرعت x,y رو تو یک record می تونید ذخیره کنید. حالا تابع دوباره فراخوانی میشه مثل قبل با پارامترهای جدید و حرکت ادامه داره تا دوباره به زمین بخوره و بعد تابع خارج میشه و باز خروجی میده تا دوباره فراخوانی بشه این چرخه ادامه داره ..... تا سرعت نزدیک صفر بشه و روی زمین وایسه.
یعنی یک تابع باید باشه که مثلا رکورد زیر رو بگیره و حرکت توپ رو نمایش بده تا توپ به زمین بخوره بعد خروجی رو هم همین رکورد پس بده. حالا تو یک حلقه اینقدر این تابع رو فراخونی کن تا قسمت سرعت مربوط به خروجی نزدیک به صفر بشه :

TBallTrans = record
x_pos, y_pos : Single;
x_speed, y_speed : Single;
end;

SAASTN
چهارشنبه 11 مرداد 1391, 00:29 صبح
مسئله یجورایی به فیزیک قضیه بر می گرده. من صحبتای Ananas رو یجور دیگه می گم: وقتی شیئ به زمین می خوره یه حرکت جدید با زاویه پی منهای زاویه برخورد شروع میشه، انگار زمان صفر شده باشه، تنها x شروع حرکت برابر x پایان حرکت قبله و بخاطر برخورد جرم با زمین یه مقدار از انرژی جنبشیش کم میشه، و این به این معنیه که سرعت اولیه حرکت جدید کسری از سرعت اولیه حرکت قبلیه. من یه شبیه سازی ساده نوشتم دیگه شاخ و برگش رو خودت اضافه کن. سرعت اولیه رو حدود 30 بدی خوب جواب میده. منم دیگه زاویه برخورد حساب نکردم و فرض کردم زاویه حرکت جدید همون زاویه پرتاب حرکت قبله:
procedure TForm1.Button1Click(Sender: TObject);
var
t, v0, theta, x0, y0, g, x, y: Double;
I: Integer;
begin
v0 := StrToFloat(Editv.Text);
theta := DegToRad(StrToFloat(Editt.Text));
y0 := StrToFloat(Edity.Text);
g := StrToFloat(Editg.Text);

t := 0;
x0 := 0;
Canvas.MoveTo(0, ClientHeight);
for I := 0 to 100 do
begin
if y < 0 then
begin
t := 0;
x0 := x;
y0 := 0;
v0 := 0.8 * v0;
end;
x := v0 * Cos(theta) * t + x0;
y := -0.5 * g * Sqr(t) + v0 * Sin(theta) * t + y0;
t := t + 0.2;
Canvas.LineTo(Round(x) * 5, ClientHeight - Round(y) * 5);
end;
end;

Ananas
چهارشنبه 11 مرداد 1391, 05:00 صبح
ببین آدمو به چه کارایی وادار میکنن، نصف شبی کدشو نوشتم :

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;

type
PVec2D = ^TVec2D;
TVec2D = packed record
x, y : Double;
end;
PPartabeh = ^TPartabeh;
TPartabeh = record
x0, y0, // start position
vx0, vy0, // start speed
t0 // start time
: Double;
end;

TForm1 = class(TForm)
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure FormCreate(Sender: TObject);
private
public

end;

const
ELLIPSE_RADIUSE = 10; // for Draw Object
ELLIPSE_COLOR = $00FF8000;
ELLIPSE_BGCOLOR = $00FFFFFF;
SQRT_UNIT_SCALE = 10;
UNIT_SCALE = SQRT_UNIT_SCALE * SQRT_UNIT_SCALE;// 100.0;
CF_G = -9.8 * UNIT_SCALE; // constant float g (phisics)
ELASTICY = 1.25;

var
Form1: TForm1;
bitm : TBitmap;
partabe : TPartabeh;
position : TVec2D;
lastPos : TVec2D;
lastTime : Double;


implementation

{$R *.dfm}

function GetNow():Double;
var
lic, lif : Int64;
begin
QueryPerformanceCounter(lic);
QueryPerformanceFrequency(lif);
Result := lic / lif;
end;

function GetPosOfPartabeh(out pOut : TVec2D; const pPart : PPartabeh):PVec2D;
var
time_ : Double;
begin
time_ := GetNow - pPart^.t0;
pOut.x := pPart^.x0 + pPart^.vx0 * time_;
pOut.y := pPart^.y0 - 0.5 * CF_G * Sqr(time_) + pPart^.vy0 * time_;
Result := @pOut;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
bitm := TBitmap.Create;
Self.Caption := 'Phisic_Partabeh_MHD_1391';
Self.Color := ELLIPSE_BGCOLOR;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Timer1.Enabled := False;
partabe.x0 := X;
partabe.y0 := Y;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssLeft in Shift then
begin
bitm.SetSize(Self.ClientWidth, Self.ClientHeight);
bitm.Canvas.Rectangle(0, 0, bitm.Width, bitm.Height);
bitm.Canvas.MoveTo(Trunc(partabe.x0), Trunc(partabe.y0));
bitm.Canvas.LineTo(X, Y);
Self.Canvas.Draw(0, 0, bitm);
end;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
partabe.vx0 := SQRT_UNIT_SCALE * (X - partabe.x0);
partabe.vy0 := SQRT_UNIT_SCALE * (Y - partabe.y0);
partabe.t0 := GetNow;
Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
v : TVec2D;
time_ : Double;
I: Integer;

if_x_0,
if_y_0,
if_x_width,
if_y_height : Boolean;

begin
(Sender as TTimer).Interval := 1;
GetPosOfPartabeh(v, @partabe);
time_ := (GetNow - lastTime) * ELASTICY;

if_x_0 := v.x <= 0;
if_y_0 := v.y <= 0;
if_x_width := v.x >= Self.ClientWidth;
if_y_height := v.y >= Self.ClientHeight;

if if_x_0 or
if_y_0 or
if_x_width or
if_y_height then
begin
partabe.vx0 := (v.x - lastPos.x) / time_;
partabe.vy0 := (v.y - lastPos.y) / time_;

if if_y_0 or if_y_height then
begin
partabe.vy0 := -partabe.vy0;

if (if_y_height) then
v.y := 2 * Self.ClientHeight - v.y
else if (if_y_0) then
v.y := -v.y;
end;

if if_x_0 or if_x_width then
begin
partabe.vx0 := -partabe.vx0;

if (if_x_width) then
v.x := 2 * Self.ClientWidth - v.x
else if (if_x_0) then
v.x := -v.x;
end;
partabe.t0 := GetNow;
partabe.x0 := v.x;
partabe.y0 := v.y;
end;

lastPos := v;
lastTime := GetNow;
bitm.SetSize(Self.ClientWidth, Self.ClientHeight);
bitm.Canvas.Brush.Color := ELLIPSE_BGCOLOR;
bitm.Canvas.Rectangle(0, 0, bitm.Width, bitm.Height);
bitm.Canvas.Brush.Color := ELLIPSE_COLOR;
bitm.Canvas.Ellipse(
Trunc(v.x - ELLIPSE_RADIUSE),
Trunc(v.y - ELLIPSE_RADIUSE),
Trunc(v.x + ELLIPSE_RADIUSE),
Trunc(v.y + ELLIPSE_RADIUSE));
bitm.Canvas.Brush.Color := ELLIPSE_BGCOLOR;
for I := 0 to 4 do
Self.Canvas.Draw(0, 0, bitm, 20);
end;

end.

//
// g = 9.8
// y = -1/2 * g.t^2 + v0.sin(t) + y0
//


این کد رو تو یک فرم خالی که فقط یک تایمر روش هست کپی کنید. همون طور که می بینید رویداد های :
OnTimer
FormMoudeDown
FormMouseMove
FormMouseUp
FormCreate
رو باید فعال کنید. فقط با چند تا کلیک موس، خودتون که واردید.
موقع اجرا باید روی صفحه با استفاده از موس کلیک و سپس درگ کنید تا پرتابه از نقطه ی کلیک شما به طرف نقطه ی درگ، پرتاب بشه. با بلند شدن طول درگ، سرعت پرتابه زیاد میشه. برخورد به 4 طرف هم محاسبه میشه و توپ از کادر بیرون نمیزنه.
حالشو ببرید.

SAASTN
چهارشنبه 11 مرداد 1391, 10:01 صبح
فوق العاده بود! دیگه چیزی باقی نذاشتی که، AngryBirdش کن بره دیگه!

me.enik
چهارشنبه 11 مرداد 1391, 10:06 صبح
سلام.
از همتون ممنونم.
ایده ی اصلی رو گرفتم.
تونستم هم تبدیلش بکنم و یه چیزی هم از آب درآمد ... !
الآن یه مشکل دیگه ای وجود داره, وقتی سرعت y را بیشتر از 0 میدیم, یعنی به اصطلاح به سمت زمین پرتاب میکنیم, توپ بعد از برخورد, دیگه بالا نمیاد, اما وقتی که به سمت هوا پرتاب میکنیم ( y >= -1 ), در اون موقع, توپ به خوبی میاد بالا.
خودم دلیلش رو نفهمیدم, گفتم سورس رو بگذارم, شاید شما فهمیدید ... !
ممنون میشوم دوباره کمکم کنید. :چشمک:

unit Unit1;

interface




uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;


type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Timer1: TTimer;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
//procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
vx,vy , x,y : real;

implementation

{$R *.dfm}




procedure partabe(vx,vy : real);
var
deltax,a,deltavy,deltay : real;
i : boolean;
begin
x:=x;
y:=y;
i := true;
vx:=strtofloat(form1.edit1.Text);
vy:=StrTofloat(form1.edit2.Text);
form1.Canvas.Ellipse(round(x),round(y),round(x)+30 ,round(y)+30);
a:=10;
while i = true do
begin
sleep(5);
form1.Canvas.Pen.Color:= clbtnface;
Form1.Canvas.Ellipse(round(x),round(y),round(x)+30 ,round(y)+30);

deltavy:=a*form1.Timer1.Interval/19000;

vy:=vy+deltavy;
deltax:=vx*form1.Timer1.Interval/19000;
deltay:=vy*form1.Timer1.Interval/19000;


y:=y+deltay;
x:=x+deltax;

form1.Canvas.Pen.Color:= clblack;
Form1.Canvas.Ellipse(round(x),round(y),round(x)+30 ,round(y)+30);

if y>900 then i := false;

end;

end;




procedure TForm1.Button1Click(Sender: TObject);
var
i : integer;
begin
for I := 1 to 10 do
begin
partabe(vx,vy);
end;
end;



procedure TForm1.Button2Click(Sender: TObject);
begin
form1.Close;
end;





procedure TForm1.FormCreate(Sender: TObject);
begin
x := 100;
y := 100;
end;

end.




آناناس, جدا خیلی خوب بود.
یعنی محشر بودش ... !
مرسی. :لبخند:



راستی, این خط زیر رو, باید با توجه به اندازه فرم خودتون, تنظیم کنید :
if y>900 then i := false;

Ananas
چهارشنبه 11 مرداد 1391, 22:20 عصر
الآن یه مشکل دیگه ای وجود داره, وقتی سرعت y را بیشتر از 0 میدیم, یعنی به اصطلاح به سمت زمین پرتاب میکنیم, توپ بعد از برخورد, دیگه بالا نمیاد, اما وقتی که به سمت هوا پرتاب میکنیم ( y >= -1 ), در اون موقع, توپ به خوبی میاد بالا.
اشکالشو پیدا کردم. کد شما رو تغییر دادم. به قسمت هایی که با XXXXXXXXXXXXXXXXXXX علامت گذاشتم دقت کن عوض شدن، حذف شدن یا اضافه شدن.

procedure partabe(vx, vy: real);
var
deltax, a, deltavy, deltay: real;
i: boolean;
begin
x := x;
y := y;
i := true;
// vx := strtofloat(Form1.Edit1.Text); // XXXXXXXXXXXXXXXXXX
// vy := strtofloat(Form1.Edit2.Text); // XXXXXXXXXXXXXXXXXX
Form1.Canvas.Ellipse(round(x), round(y), round(x) + 30, round(y) + 30);
a := 10;
while i = true do
begin
sleep(5);
Form1.Canvas.Pen.Color := clbtnface;
Form1.Canvas.Ellipse(round(x), round(y), round(x) + 30, round(y) + 30);

deltavy := a / 19.0; // XXXXXXXXXXXXXXXX

vy := vy + deltavy;
deltax := vx / 19.0; // XXXXXXXXXXXXXXXX
deltay := vy / 19.0; // XXXXXXXXXXXXXXXX

y := y + deltay;
x := x + deltax;

Form1.Canvas.Pen.Color := clblack;
Form1.Canvas.Ellipse(round(x), round(y), round(x) + 30, round(y) + 30);

if y > Form1.ClientHeight then // XXXXXXXXXXXXXXXX
begin
i := false;
//ShowMessage(FloatToStr(vy)); // XXXXXXXXXXXXXXXX
if Unit1.vy > 0 then // XXXXXXXXXXXXXXXX
Unit1.vy := -Unit1.vy; // XXXXXXXXXXXXXXXX
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
x := 100;
y := 100;
vx := StrToFloatDef(Form1.Edit1.Text, 0); // XXXXXXXXXXXXXXXXX
vy := StrToFloatDef(Form1.Edit2.Text, 0); // XXXXXXXXXXXXXXXXX
for i := 1 to 10 do
begin
partabe(vx, vy);
end;
end;

آفرین فکر میکنم روش شما بهتر باشه که تو لحظه نسبت به سرعتش مکان بعدی محاسبه میشه. روش من با اطلاعات اولیه ی هنگام پرتاب کار میکنه و خیلی پویا نیست و یک قطعه از حرکت رو شبیه سازی میکنه بخاطر همین مجبوریم وقتی به زمین خورد دوباره تابع رو اجرا کنیم. فکر میکنم باید دنبال فرمولی باشیم که وابسته به نقطه ی شروع نباشه و تو هر لحظه با استفاده از سرعت و شتاب مکان بعد رو پیدا کنه.
کد شما چند جا ابهام داره که یکیش تو استفاده از متغیر های همنام بیرون تابع و توی تابع هست . یکی دیگشم استفاده از Interval تایمر هست که یک مقدار ثابت رو بر می گردونه و اصلا نیازی به وجود تایمر در اینجا نیست و من اون قسمت رو ساده کردم. سعی کنید تا میشه از مقادیر ثابت استفاده کنید اگه نشد از توابع جمع و تفریق اگه نشد ضرب اگه نشد تقسیم اگه نشد للگاریتم و توان و مثلثات. سعی کردم به ترتیب سرعتشون بنویسم. مثلا اگه می تونید در 0.5 ضرب کنید ، به دو تقسیم نکنید. اگه می خواید از رادیکال دو استفاده کنید از تابع Sqrt استفاده نکنید از مقدار 0.7071 کنید. اگه دقت کنید من تو کدم از تابع سینوس و کسینوس استفاده نکردم چون اول استفاده کرده بودم تا تست کنم بعد که دیدم فرمول درسته کد رو ساده کردم تا محاسبه ی sin و cos داخل حلقه، از کد حذف بشه.

Ananas
چهارشنبه 11 مرداد 1391, 22:23 عصر
خیلی ممنون از لطف دوستان. کد رو با کمک برادرم که فارغ التحصیل رشته ی فیزیک هست نوشتم. تو نوشتن فرمول های فیزیکی همیشه بهم کمک میکنه ازش ممنونم. کدم رو تغییر دادم. این بار یک فرم اپلیکیشن خالی بدون هیچ چیزی بسازید و کد رو کپی کنید داخل یونیت بعد formcreate رو نسبت بدید.
تو این نمونه چند تا توپ می تونید پشت سر هم بسازید. یه تغییراتی هم تو اشیا دادم. شعاع توپ رو هم برای برخورد به دیواره ها و زمین و سقف لحاظ می کنه. می خوام برخورد توپ ها رو هم براش تعریف کنم. لطفا راهنمایی کنید و نظر بدید. با کلیک چپ درگ کنید تا توپ ساخته شه و با کلیک راست توپ ها رو حذف کنید (با هر کلیک هر جای صفحه یک توپ از اول لیست حذف میشه.)

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Generics.Collections,
Vcl.StdCtrls;

type
PVec2D = ^TVec2D;
TVec2D = packed record
x, y : Double;
procedure SetVal(x_, y_ : Single);
end;
PPartabeh = ^TPartabeh;
TPartabeh = record
x0, y0, // start position
vx0, vy0, // start speed
t0 // start time
: Double;
end;

TBall = class
Partabe : TPartabeh;
lastPos : TVec2D;
lastTime : Double;
Color : TColor;
Radiuse : Integer;
function GetPosOfPartabeh(out pOut : TVec2D):PVec2D;
procedure CheckCollectionRect(r : TRect);
constructor Create;
end;

TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
public
MouseShift : TShiftState;
procedure MyTimerTimer(Sender: TObject);
procedure MyMouseDown(
Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure MyMouseUp(
Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure MyMouseMove(
Sender: TObject;
Shift: TShiftState;
X, Y: Integer);
end;

const
ELLIPSE_MIN_RADIUSE = 4; // for Draw Object
ELLIPSE_MAX_RADIUSE = 32;
ELLIPSE_COLOR = $00FF8000;
ELLIPSE_BGCOLOR = $00FFFFFF;
SQRT_UNIT_SCALE = 10;
UNIT_SCALE = SQRT_UNIT_SCALE * SQRT_UNIT_SCALE;// 100.0;
CF_G = -9.8 * UNIT_SCALE; // constant float g (phisics)
ELASTICY = 1.1;

var
ballList : TList<TBall>;
Form1 : TForm1;
MHDPaintBox : TPaintBox;
MHDTimer : TTimer;
MHDLabel : TLabel;
bitm, backBitm : TBitmap;
currentBall : TBall;
start_Point,end_Point : TPoint;


implementation

{$R *.dfm}

procedure TVec2D.SetVal(x_, y_ : Single);
begin
Self.x := x_;
Self.y := y_;
end;

function GetNow():Double;
var
lic, lif : Int64;
begin
QueryPerformanceCounter(lic);
QueryPerformanceFrequency(lif);
Result := lic / lif;
end;

constructor TBall.Create;
begin
Self.Color := Random($00FFFFFF);
Self.Radiuse := Random(ELLIPSE_MAX_RADIUSE - ELLIPSE_MIN_RADIUSE) + ELLIPSE_MIN_RADIUSE;
end;

function TBall.GetPosOfPartabeh(out pOut : TVec2D):PVec2D;
var
time_ : Double;
begin
time_ := GetNow - Self.Partabe.t0;
pOut.x := Self.Partabe.x0 + Self.Partabe.vx0 * time_;
pOut.y := Self.Partabe.y0 - 0.5 * CF_G * Sqr(time_) + Self.Partabe.vy0 * time_;
Result := @pOut;
end;

procedure TBall.CheckCollectionRect(r : TRect);
var
if_x_0,
if_y_0,
if_x_width,
if_y_height : Boolean;

v : TVec2D;
time_ : Double;
begin
GetPosOfPartabeh(v);
time_ := (GetNow - lastTime) * ELASTICY;

r := Rect(
Self.Radiuse,
Self.Radiuse,
r.Right - Self.Radiuse,
r.Bottom - Self.Radiuse);

if_x_0 := v.x <= r.Left;
if_y_0 := v.y <= r.Top;
if_x_width := v.x >= r.Right; // Self.ClientWidth;
if_y_height := v.y >= r.Bottom; // Self.ClientHeight;

if if_x_0 or
if_y_0 or
if_x_width or
if_y_height then
begin
Self.Partabe.vx0 := (v.x - lastPos.x) / time_;
Self.Partabe.vy0 := (v.y - lastPos.y) / time_;

if if_y_0 or if_y_height then
begin
Self.Partabe.vy0 := -Self.Partabe.vy0;

if (if_y_height) then
v.y := r.Bottom + (r.Bottom - v.y) / ELASTICY
else // if (if_y_0)
v.y := r.Top + (r.Top - v.y) / ELASTICY;
end
else // if if_x_0 or if_x_width
begin
Self.Partabe.vx0 := -Self.Partabe.vx0;

if (if_x_width) then
v.x := r.Right + (r.Right - v.x) / ELASTICY
else // if (if_x_0)
v.x := r.Left + (r.Left - v.x) / ELASTICY;
end;

Self.Partabe.t0 := GetNow;
Self.Partabe.x0 := v.x;
Self.Partabe.y0 := v.y;
end;

Self.lastPos := v;
Self.lastTime := GetNow;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
pnl : TPanel;
begin
ballList := TList<TBall>.Create;
bitm := TBitmap.Create;
backBitm := TBitmap.Create;
Self.Caption := 'Phisic_Partabeh_MHD_1391';
Self.Color := ELLIPSE_BGCOLOR;

pnl := TPanel.Create(Self);
pnl.ShowCaption := False;
pnl.Caption := '';
pnl.Height := 100;
pnl.ParentBackground := False;
pnl.ParentColor := False;
pnl.Color := $00464139;
pnl.Parent := Self;
pnl.Align := alTop;

MHDLabel := TLabel.Create(Self);
MHDLabel.Parent := pnl;
MHDLabel.WordWrap := True;
MHDLabel.Font.Size := 12;
MHDLabel.Font.Color := $00FFFFFF;
MHDLabel.Left := 20;

MHDPaintBox := TPaintBox.Create(Self);
MHDPaintBox.Parent := Self;
MHDPaintBox.Align := alClient;
MHDPaintBox.OnMouseDown := MyMouseDown;
MHDPaintBox.OnMouseMove := MyMouseMove;
MHDPaintBox.OnMouseUp := MyMouseUp;

MHDTimer := TTimer.Create(Self);
MHDTimer.OnTimer := MyTimerTimer;
MHDTimer.Interval := 1;
MHDTimer.Enabled := True;
end;

procedure TForm1.MyMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
MouseShift := Shift;
if ssLeft in Shift then
begin
start_Point := Point(X, Y);
end_Point := Point(X, Y);
end else if (ssRight in MouseShift) and
(ballList.Count > 0) then
ballList.Delete(0);
end;

procedure TForm1.MyMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssLeft in MouseShift then
begin
end_Point := Point(X, Y);
end;
end;

procedure TForm1.MyMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if ssLeft in MouseShift then
begin
end_Point := Point(X, Y);
currentBall := TBall.Create;
currentBall.Partabe.x0 := start_Point.x;
currentBall.Partabe.y0 := start_Point.y;
currentBall.Partabe.vx0 := SQRT_UNIT_SCALE * (X - currentBall.Partabe.x0);
currentBall.Partabe.vy0 := SQRT_UNIT_SCALE * (Y - currentBall.Partabe.y0);
currentBall.Partabe.t0 := GetNow;
start_Point := end_Point;
ballList.Add(currentBall);
end;
MouseShift := Shift;
end;

procedure TForm1.MyTimerTimer(Sender: TObject);
var
i : Integer;
r : TRect;

begin
(Sender as TTimer).Interval := 1;

bitm.SetSize(MHDPaintBox.ClientWidth, MHDPaintBox.ClientHeight);
backBitm.SetSize(bitm.Width, bitm.Height);

bitm.Canvas.Brush.Color := ELLIPSE_BGCOLOR;
bitm.Canvas.Rectangle(0, 0, bitm.Width, bitm.Height);
backBitm.Canvas.Draw(0, 0, bitm, 64);

for i := 0 to (ballList.Count - 1) do
begin
backBitm.Canvas.Brush.Color := ballList[i].Color;
ballList[i].CheckCollectionRect(MHDPaintBox.ClientRect);
backBitm.Canvas.Ellipse(
Trunc(ballList[i].lastPos.x - ballList[i].Radiuse),
Trunc(ballList[i].lastPos.y - ballList[i].Radiuse),
Trunc(ballList[i].lastPos.x + ballList[i].Radiuse),
Trunc(ballList[i].lastPos.y + ballList[i].Radiuse));
end;
backBitm.Canvas.Brush.Color := ELLIPSE_BGCOLOR;

MHDPaintBox.Canvas.Draw(0, 0, backBitm);
MHDPaintBox.Canvas.MoveTo(start_Point.x, start_Point.y);
MHDPaintBox.Canvas.LineTo(end_Point.x , end_Point.y);

MHDLabel.Caption := FloatToStr(Trunc(
1000.0 * Sqrt( // radical (x^2 + y^2)
Sqr(end_Point.X - start_Point.X) + // x ^ 2
Sqr(end_Point.Y - start_Point.Y)) // y ^ 2
) / 1000.0);
MHDLabel.Repaint;
end;

end.

//
// g = 9.8
// y = -1/2 * g.t^2 + v0.sin(t) + y0
//

amin1softco
پنج شنبه 12 مرداد 1391, 00:33 صبح
خیلی باحال بود خوشمان آمد :دی

SAASTN
پنج شنبه 12 مرداد 1391, 04:42 صبح
حالا که اینجوری شد اینم برخورد توپا با هم:
unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Generics.Collections,
Vcl.StdCtrls;

type
PVec2D = ^TVec2D;
TVec2D = packed record
x, y : Double;
procedure SetVal(x_, y_ : Single);
end;
PPartabeh = ^TPartabeh;
TPartabeh = record
x0, y0, // start position
vx0, vy0, // start speed
t0 // start time
: Double;
end;

TBall = class
Partabe : TPartabeh;
lastPos : TVec2D;
lastTime : Double;
Color : TColor;
Radiuse : Integer;
function GetPosOfPartabeh(out pOut : TVec2D):PVec2D;
procedure CheckCollectionRect(r : TRect);
procedure CheckOtherBallsCollision(Ball: TBall);
constructor Create;
end;

TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
public
MouseShift : TShiftState;
procedure MyTimerTimer(Sender: TObject);
procedure MyMouseDown(
Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure MyMouseUp(
Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure MyMouseMove(
Sender: TObject;
Shift: TShiftState;
X, Y: Integer);
end;

const
ELLIPSE_MIN_RADIUSE = 4; // for Draw Object
ELLIPSE_MAX_RADIUSE = 32;
ELLIPSE_COLOR = $00FF8000;
ELLIPSE_BGCOLOR = $00FFFFFF;
SQRT_UNIT_SCALE = 10;
UNIT_SCALE = SQRT_UNIT_SCALE * SQRT_UNIT_SCALE;// 100.0;
CF_G = -9.8 * UNIT_SCALE; // constant float g (phisics)
ELASTICY = 1.8;

var
ballList : TList<TBall>;
Form1 : TForm1;
MHDPaintBox : TPaintBox;
MHDTimer : TTimer;
MHDLabel : TLabel;
bitm, backBitm : TBitmap;
currentBall : TBall;
start_Point,end_Point : TPoint;


implementation

{$R *.dfm}

procedure TVec2D.SetVal(x_, y_ : Single);
begin
Self.x := x_;
Self.y := y_;
end;

function GetNow():Double;
var
lic, lif : Int64;
begin
QueryPerformanceCounter(lic);
QueryPerformanceFrequency(lif);
Result := lic / lif;
end;

procedure TBall.CheckOtherBallsCollision(Ball: TBall);
var
P1, P2: TVec2D;
t, t1, t2, m1, m2, vx1, vy1, vx2, vy2, ux1, uy1, ux2, uy2: Double;
begin
Self.GetPosOfPartabeh(P1);
Ball.GetPosOfPartabeh(P2);
if Sqrt(Sqr(P1.x-p2.x)+Sqr(P1.y-P2.y))<Ball.Radiuse+Radiuse then
begin
t := GetNow;
t1 := (t - Self.lastTime)/ELASTICY;
t2 := (t - Ball.lastTime)/ELASTICY;
m1 := Pi * Sqr(Self.Radiuse);
m2 := Pi * Sqr(Ball.Radiuse);

// vx1 := Self.Partabe.vx0;
// vy1 := CF_G * t1 + Self.Partabe.vy0;
// vx2 := Ball.Partabe.vx0;
// vy2 := CF_G * t2 + Ball.Partabe.vy0;

vx1 := (P1.x - Self.lastPos.x) / t1;
vy1 := (P1.y - Self.lastPos.y) / t1;

vx2 := (P2.x - Ball.lastPos.x) / t2;
vy2 := (P2.y - Ball.lastPos.y) / t2;

ux1 := (vx1 * (m1-m2) + 2*m2*vx2)/(m1+m2);
uy1 := (vy1 * (m1-m2) + 2*m2*vy2)/(m1+m2);
ux2 := (vx2 * (m2-m1) + 2*m1*vx1)/(m1+m2);
uy2 := (vy2 * (m2-m1) + 2*m1*vy1)/(m1+m2);

Self.Partabe.x0 := P1.x;
Self.Partabe.y0 := P1.y;

Self.Partabe.vx0 := ux1;
Self.Partabe.vy0 := uy1;
Self.Partabe.t0 := t;

Ball.Partabe.x0 := P2.x;
Ball.Partabe.y0 := P2.y;

Ball.Partabe.vx0 := ux2;
Ball.Partabe.vy0 := uy2;
Ball.Partabe.t0 := t;
end;
end;

constructor TBall.Create;
begin
Self.Color := Random($00FFFFFF);
Self.Radiuse := Random(ELLIPSE_MAX_RADIUSE - ELLIPSE_MIN_RADIUSE) + ELLIPSE_MIN_RADIUSE;
end;

function TBall.GetPosOfPartabeh(out pOut : TVec2D):PVec2D;
var
time_ : Double;
begin
time_ := GetNow - Self.Partabe.t0;
pOut.x := Self.Partabe.x0 + Self.Partabe.vx0 * time_;
pOut.y := Self.Partabe.y0 - 0.5 * CF_G * Sqr(time_) + Self.Partabe.vy0 * time_;
Result := @pOut;
end;

procedure TBall.CheckCollectionRect(r : TRect);
var
if_x_0,
if_y_0,
if_x_width,
if_y_height : Boolean;

v : TVec2D;
time_ : Double;
begin
GetPosOfPartabeh(v);
time_ := (GetNow - lastTime) * ELASTICY;

r := Rect(
Self.Radiuse,
Self.Radiuse,
r.Right - Self.Radiuse,
r.Bottom - Self.Radiuse);

if_x_0 := v.x <= r.Left;
if_y_0 := v.y <= r.Top;
if_x_width := v.x >= r.Right; // Self.ClientWidth;
if_y_height := v.y >= r.Bottom; // Self.ClientHeight;

if if_x_0 or
if_y_0 or
if_x_width or
if_y_height then
begin
Self.Partabe.vx0 := (v.x - lastPos.x) / time_;
Self.Partabe.vy0 := (v.y - lastPos.y) / time_;

if if_y_0 or if_y_height then
begin
Self.Partabe.vy0 := -Self.Partabe.vy0;

if (if_y_height) then
v.y := r.Bottom + (r.Bottom - v.y) / ELASTICY
else // if (if_y_0)
v.y := r.Top + (r.Top - v.y) / ELASTICY;
end
else // if if_x_0 or if_x_width
begin
Self.Partabe.vx0 := -Self.Partabe.vx0;

if (if_x_width) then
v.x := r.Right + (r.Right - v.x) / ELASTICY
else // if (if_x_0)
v.x := r.Left + (r.Left - v.x) / ELASTICY;
end;

Self.Partabe.t0 := GetNow;
Self.Partabe.x0 := v.x;
Self.Partabe.y0 := v.y;
end;

Self.lastPos := v;
Self.lastTime := GetNow;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
pnl : TPanel;
begin
ballList := TList<TBall>.Create;
bitm := TBitmap.Create;
backBitm := TBitmap.Create;
Self.Caption := 'Phisic_Partabeh_MHD_1391';
Self.Color := ELLIPSE_BGCOLOR;

pnl := TPanel.Create(Self);
pnl.ShowCaption := False;
pnl.Caption := '';
pnl.Height := 100;
pnl.ParentBackground := False;
pnl.ParentColor := False;
pnl.Color := $00464139;
pnl.Parent := Self;
pnl.Align := alTop;

MHDLabel := TLabel.Create(Self);
MHDLabel.Parent := pnl;
MHDLabel.WordWrap := True;
MHDLabel.Font.Size := 12;
MHDLabel.Font.Color := $00FFFFFF;
MHDLabel.Left := 20;

MHDPaintBox := TPaintBox.Create(Self);
MHDPaintBox.Parent := Self;
MHDPaintBox.Align := alClient;
MHDPaintBox.OnMouseDown := MyMouseDown;
MHDPaintBox.OnMouseMove := MyMouseMove;
MHDPaintBox.OnMouseUp := MyMouseUp;

MHDTimer := TTimer.Create(Self);
MHDTimer.OnTimer := MyTimerTimer;
MHDTimer.Interval := 1;
MHDTimer.Enabled := True;
end;

procedure TForm1.MyMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
MouseShift := Shift;
if ssLeft in Shift then
begin
start_Point := Point(X, Y);
end_Point := Point(X, Y);
end else if (ssRight in MouseShift) and
(ballList.Count > 0) then
ballList.Delete(0);
end;

procedure TForm1.MyMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssLeft in MouseShift then
begin
end_Point := Point(X, Y);
end;
end;

procedure TForm1.MyMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if ssLeft in MouseShift then
begin
end_Point := Point(X, Y);
currentBall := TBall.Create;
currentBall.Partabe.x0 := start_Point.x;
currentBall.Partabe.y0 := start_Point.y;
currentBall.Partabe.vx0 := SQRT_UNIT_SCALE * (X - currentBall.Partabe.x0);
currentBall.Partabe.vy0 := SQRT_UNIT_SCALE * (Y - currentBall.Partabe.y0);
currentBall.Partabe.t0 := GetNow;
start_Point := end_Point;
ballList.Add(currentBall);
end;
MouseShift := Shift;
end;

procedure TForm1.MyTimerTimer(Sender: TObject);
var
i : Integer;
r : TRect;
j: Integer;

begin
(Sender as TTimer).Interval := 1;

bitm.SetSize(MHDPaintBox.ClientWidth, MHDPaintBox.ClientHeight);
backBitm.SetSize(bitm.Width, bitm.Height);

bitm.Canvas.Brush.Color := ELLIPSE_BGCOLOR;
bitm.Canvas.Rectangle(0, 0, bitm.Width, bitm.Height);
backBitm.Canvas.Draw(0, 0, bitm, 64);

for i := 0 to (ballList.Count - 1) do
ballList[i].CheckCollectionRect(MHDPaintBox.ClientRect);
for i := 0 to ballList.Count - 2 do
for j := i+1 to ballList.Count -1 do
ballList[i].CheckOtherBallsCollision(ballList[j]);
for i := 0 to (ballList.Count - 1) do
begin
backBitm.Canvas.Brush.Color := ballList[i].Color;
backBitm.Canvas.Ellipse(
Trunc(ballList[i].lastPos.x - ballList[i].Radiuse),
Trunc(ballList[i].lastPos.y - ballList[i].Radiuse),
Trunc(ballList[i].lastPos.x + ballList[i].Radiuse),
Trunc(ballList[i].lastPos.y + ballList[i].Radiuse));
end;
backBitm.Canvas.Brush.Color := ELLIPSE_BGCOLOR;

MHDPaintBox.Canvas.Draw(0, 0, backBitm);
MHDPaintBox.Canvas.MoveTo(start_Point.x, start_Point.y);
MHDPaintBox.Canvas.LineTo(end_Point.x , end_Point.y);

MHDLabel.Caption := FloatToStr(Trunc(
1000.0 * Sqrt( // radical (x^2 + y^2)
Sqr(end_Point.X - start_Point.X) + // x ^ 2
Sqr(end_Point.Y - start_Point.Y)) // y ^ 2
) / 1000.0);
MHDLabel.Repaint;
end;

end.

//
// g = 9.8
// y = -1/2 * g.t^2 + v0.sin(t) + y0

فقط یه مشکلی داره، وقتی توپا با هم برخورد می کنن با این که مجموع سرعت قبل و بعد ضربه تو هر دو یکیه ولی انگار یه انرژی در اثر ضربه ایجاد میشه و باعث میشه حرکت سریعتر انجام بشه و در نتیجه به جای اینکه توپا بعد از یه مدت ثابت بشن، ممکنه مدتها به حرکت ادامه بدن، حتی بالا بردن ضریب الاستیسیته هم کمکی نمی کنه. همونطور که تو کد مشخصه من سرعت توپا بعد از ضربه رو از روی فرمولای مربوط به برخورد یک بعدی (http://en.wikipedia.org/wiki/Elastic_collision) به دست آوردم، یه بار برای جهت x و یه بار برای جهت y. حالا ممکنه قوانین برخورد تو فضای دو بعدی کاملا با برخورد تو فضای یه بعدی متفاوت باشه یا این که برخورد تو حرکت شتابدار و حرکت بدون شتاب متفاوت باشه و سرعت در جهت y یجور دیگه محاسبه بشه. یه سوالی از برادرت بپرس ببین می تونه کمک کنه.
از اونور برای اینکه بحث کلا فیزیکی نشه یه نکته رو هم بگم بد نیست. سعی کن تو برنامه های محاسباتی تمام مقادیر رو تو واحد استاندارد نگه داری. یعنی هر جا مقداری به عنوان زمان نگه داری میشه یا برای تابعی ارسال میشه در واحد ثانیه باشه، و به همین ترتیب مقدایر دیگه، طولا همه متر باشن و سرعتا همه متر بر ثانیه. هیچ وقت ضرائب رو تو محاسبات دخیل نکن. اگه برای خروجی گرفتن نیاز به تبدیل واحد یا scale و ... داری، همه این کارا رو فقط همون موقع خروجی گرفتن انجام بده. حالا خروجی چه تصویری باشه، چه یه ریپورت باشه چه فایل باشه یا هرچیز دیگه. اگر هم مقادیر از ورودی میان همون لحظه ای که داری از ورودی می خونی به واحد استاندارد ببرشون بعد استفاده کن. این کار باعث میشه که موقع دیباگ یه ذهنیت درست از مقادیر داشته باشی و بتونی اونها رو با هم مقایسه کنی و همینطور فرمولا رو بتونی به همون صورت استانداردشون کد کنی. به این ترتیب تما بخشهای ورودی-خروجی از بخشای محاسباتی جدا میشن و کار دیباگ تو بخشای محاسباتی خیلی ساده تر میشه.

me.enik
پنج شنبه 12 مرداد 1391, 09:49 صبح
آناناس, خیلی ازت ممنونم.
کمک خوبی کردی. :دی

------------------------

به به ... !
ببین چه کل کلی اینجا راه افتاده !
همین جوری ادامه بدین, میتونیم بازی angry birds take off ( نسخه ای که قراره خودمون عرضه کنیم ... ! ), در عرض کمتر از 5-6 هفته دیگه, به بازار های جهانی عرضه خواهد شد. :لبخند:

SAASTN
پنج شنبه 12 مرداد 1391, 12:45 عصر
همین جوری ادامه بدین, میتونیم بازی angry birds take off ( نسخه ای که قراره خودمون عرضه کنیم ... ! ), در عرض کمتر از 5-6 هفته دیگه, به بازار های جهانی عرضه خواهد شد.
واقعا دور از ذهن نیست، حالا منظورم دقیقا AngyBirds نیست. ولی اگه چندتا چیز دیگه به همین کد اضافه بشه میشه ازش به عنوان یه موتور فیزیکی تو خیلی از بازیای ساده استفاده کرد. اضافه شدن موانع به محیط، تعیین مشخصات استاتیکی هر کدوم از اشیائ بصورت جداگانه، اضافه شدن منابع انرژی به اشیائ (یه چیزی مثل موشک) و تو مراحل بعدی اضافه شدن گشتاور و اصطکاک و خارج کردن اشیائ از محدودیت شکل! و بعدم سه بعدی کردن اون. اضافه کردن المانای فیزیکی دیگه هم ممکنه اگه کاربردی داشته باشه، مثل نخ و فنر و چرخ و گاری و ماشین آتود و ... (واقعا تمومی نداره).
من یادمه شما تو تاپیک فنر گفتی قصد داری چندتا برنامه شبیه سازی بنویسی و احتمالا شبیه سازی پرتابه هم تو همون راستاست. پیشنهاد من اینه که یه موتور فیزیکی (منظورم موتور برنامه نویسیه) رو نقطه هدف قرار بدی و بشینی یه سری مطالعات در مورد اون انجام بدی. اگه یه پایه خوب برای همچین موتوری نوشته بشه میشه سر فرصت همه اون مواردی که اول گفتم رو بهش اضافه کرد. تنها نکته ای که باید رعایت بشه برخورد کاملا علمی و ریاضی با قضیه هست.

me.enik
پنج شنبه 12 مرداد 1391, 13:19 عصر
آره, راستش خودم هم این چیزا رو خیلی دوست دارم.
برای همین هم هست که به دنبالشونم.
ممنون از توصیه ای که کردی.
تمام سعیم رو میکنم.
خیلی خوب می شد اگر چند تا شبیه سازی قشنگ رو لیست میکردید, تا بعد از اینکه کار حرکت پرتابه به یه جایی رسید, اون موقع بروم سراغ اونها.
فقط اجزای لیست, به هم مرتبط باشن تا یه چیز قشنگی از آب در بیاد ... !

Ananas
جمعه 13 مرداد 1391, 01:11 صبح
فقط یه مشکلی داره، وقتی توپا با هم برخورد می کنن با این که مجموع سرعت قبل و بعد ضربه تو هر دو یکیه ولی انگار یه انرژی در اثر ضربه ایجاد میشه و باعث میشه حرکت سریعتر انجام بشه و در نتیجه به جای اینکه توپا بعد از یه مدت ثابت بشن، ممکنه مدتها به حرکت ادامه بدن، حتی بالا بردن ضریب الاستیسیته هم کمکی نمی کنه. همونطور که تو کد مشخصه من سرعت توپا بعد از ضربه رو از روی فرمولای مربوط به برخورد یک بعدی (http://en.wikipedia.org/wiki/Elastic_collision) به دست آوردم، یه بار برای جهت x و یه بار برای جهت y. حالا ممکنه قوانین برخورد تو فضای دو بعدی کاملا با برخورد تو فضای یه بعدی متفاوت باشه یا این که برخورد تو حرکت شتابدار و حرکت بدون شتاب متفاوت باشه و سرعت در جهت y یجور دیگه محاسبه بشه. یه سوالی از برادرت بپرس ببین می تونه کمک کنه.
آفرین. خیلی جالبه. داره درست عمل میکنه ولی فقط یه مشکل هندسی داره که یکمی هم مربوط به نرم افزار میشه. من این موضوع رو به اخوی گفتم و یه اطلاعاتی بهم داد و روش فکر کردم. می دونم باید چه کار کنیم ولی نمی دونم چطور باید اجرا بشه (دارم روش فکر میکنم). اشکال ها ازین قراره :
1 - تو سرعت های بالا جسم ها از هم رد میشن. چون ما داریم فریم به فریم محاسبه انجام می دیم طبیعیه که این خطا رخ بده و به نقل از اخوی، تو نرم افزار Interactive Phisics هم همین مشکل وجود داره. تو بازی ماشین هم می بینیم وقتی رمز می زنیم و سرعت از حد عادی خیلی بیشتر میشه ماشین از تو دیوار رد میشه. مثلا تو لحظه ی t0 دو تا توپ دارن به هم نزدیک میشن تا برخورد کنن و تو لحظه ی t1 (فریم بعدی) توپ ها برخورد کردن و از هم رد شدن ولی کد ما اینو نمی فهمه و فی ما بین (چی گفتم!) دو فریم رو بیخیال میشه.
2 - تو کدی که شما زحمت کشیدید نوشتید برای collision ، بعد از اینکه سرعت اولیه ها vx0 , vy0 آپدیت شدن باید مکان اولیه ها هم آپدیت بشن ولی تو این تابع مستقیم مکان محاسبه شده در زمان تو هم رفتگی دو تا توپ رو بهش می دیم که اشتباهه. ببینید تو یک فریمی برنامه چک کرده و متوجه شده که توپ a و توپ b داخل هم دیگن (فاصله ی مرکز دو دایره کمتر از مجموع شعاع ها هست) حالا که متوجه شده باید دو تا توپ رو از هم دیگه بکشه بیرون و بهتر بگم مکان درست توپ رو نسبت به برخوردی که بین دو فریم اخیر رخ داده و بعد توپ ها از هم دور شدن رو باید حساب کنه که نمیکنه. بعد تو فریم بعدی برنامه دوباره میاد چک میکنه که توپ ها داخل هم هستن یا نه، میبینه داخل هم هستن و ما سرعت هاشونم تو فریم قبل عوض کردیم . حالا با توجه به lastPos و lastTime که اینها هم بروز نشدن دوباره میاد برخوردشون میده قبل از اینکه توپ ها فرصت کنن با سرعت جدید از هم جدا بشن. نتیجش اینه که تو توپ های بزرگ و تو سرعت های بالا (نرسیدن فریم ها برای محاسبه سریع که قبل از اینکه بیشتر تو هم فرو برن برخورد تشخیص داده بشه.) توپ چند دفعه برخورد داده میشه در حالی که ما باید بعد از یک برخورد اونها رو از هم دور کنیم. حالا پیدا کنید پرتقال فروش رو.


از اونور برای اینکه بحث کلا فیزیکی نشه یه نکته رو هم بگم بد نیست. سعی کن تو برنامه های محاسباتی تمام مقادیر رو تو واحد استاندارد نگه داری. یعنی هر جا مقداری به عنوان زمان نگه داری میشه یا برای تابعی ارسال میشه در واحد ثانیه باشه، و به همین ترتیب مقدایر دیگه، طولا همه متر باشن و سرعتا همه متر بر ثانیه. هیچ وقت ضرائب رو تو محاسبات دخیل نکن. اگه برای خروجی گرفتن نیاز به تبدیل واحد یا scale و ... داری، همه این کارا رو فقط همون موقع خروجی گرفتن انجام بده. حالا خروجی چه تصویری باشه، چه یه ریپورت باشه چه فایل باشه یا هرچیز دیگه. اگر هم مقادیر از ورودی میان همون لحظه ای که داری از ورودی می خونی به واحد استاندارد ببرشون بعد استفاده کن. این کار باعث میشه که موقع دیباگ یه ذهنیت درست از مقادیر داشته باشی و بتونی اونها رو با هم مقایسه کنی و همینطور فرمولا رو بتونی به همون صورت استانداردشون کد کنی. به این ترتیب تما بخشهای ورودی-خروجی از بخشای محاسباتی جدا میشن و کار دیباگ تو بخشای محاسباتی خیلی ساده تر میشه.
دقیقا موافقم. تو فکر بودم که این کار رو بکنم و با واحد های SI پیش برم. ممنون از تذکرت. ایشالا تو برنامه های بعدی.


آناناس, خیلی ازت ممنونم.
کمک خوبی کردی. :دی
زنده باشی.

به به ... !
ببین چه کل کلی اینجا راه افتاده !

تا باشه ازین مباحث علمی.

همین جوری ادامه بدین, میتونیم بازی angry birds take off ( نسخه ای که قراره خودمون عرضه کنیم ... ! ), در عرض کمتر از 5-6 هفته دیگه, به بازار های جهانی عرضه خواهد شد. :لبخند:
یوقت دیدی ساختم چون با DirectX هم میتونم نمایشش رو سریع و با کیفیت کنم.

ولی اگه چندتا چیز دیگه به همین کد اضافه بشه میشه ازش به عنوان یه موتور فیزیکی تو خیلی از بازیای ساده استفاده کرد.
خوب فکریه ولی نه روی این کد. می خوام برای بازی ماشین محاسبات فیزیکی بنویسم و تو یه یونیت مستقل و با مقادیر درست فیزیکی و شایدم به زبان c++ درستش کنم. ولی الان نمی خوام شروع کنم می خوام تجربه و اطلاعاتم بیشتر بشه تا یه چیزی کاربردی ساخته بشه. اینا هم تمرین به حساب میاد.
me.enik جون هم که ماشالا پایه تو کارای فیزیکیه:بوس:. ادامه بده من باهاتم.

me.enik
جمعه 13 مرداد 1391, 11:27 صبح
me.enik جون هم که ماشالا پایه تو کارای فیزیکیه:بوس:. ادامه بده من باهاتم.
تا ببینیم خدا چی میخواد ... !
فعلا من با همین خرده پروژه ها, پیش میرم, یهو دیدی یه روز جو منو گرفت و اون انگری بیردز رو ساختم. :چشمک: :لبخند:
بازم تشکر میکنم.
راستی, برای ساخت اون موتور بازی که بالا قول دادم ( کوو ... !؟ ), فعلا هنوز بچم !! بزار بزرگتر بشم, تا بازم ببینیم خدا چی میخواد.