![]() |
Problem mit Multiplikation
Hallo, unzwar habe ich folgendes Problem in einer simplen Anweisung:
Ball.YSpeed := Ball.YSpeed * -1; YSpeed ist im Testfall -1, wenn ich es aber wie oben mit -1 multipliziere bleibt es -1. Wenn ich es mit z.B. -3 multipliziere kommt -3 heraus, aber bei einer Multiplikation mit 3 kommt auch -3 heraus. Ich kann überhaupt nicht nachvollziehen warum das nicht funktioniert. Bitte um eine schnelle Antwort |
AW: Problem mit Multiplikation
Quelltext?
|
AW: Problem mit Multiplikation
Herzlich Willkommen im Forum!
Aber das... Zitat:
Hetzen is hier nich.:-D |
AW: Problem mit Multiplikation
Naja Quellcode wird jetzt auch nicht viel ändern weil Ball.YSpeed an einem anderem Punkt nur auf -1 gesetzt wird. Wenn ich z.b. folgendes if ausführe wird Ball.YSpeed auf 1 gesetzt weil es ja -1 ist. Diese Anweisung funktioniert ohne Probleme. Warum aber eine simple Multiplikation mit -1 nicht funktioniert?
if Ball.YSpeed = -1 then begin Ball.YSpeed := 1; end; fYSpeed ist als single deklariert, falls es vlt. daran liegt: fYSpeed : Single; Im Endeffekt will ich nur einen Vorzeichenumkehr machen, die halt mit *-1. Habe nun auch schon andere Varianten ausprobiert: Ball.YSpeed := 0-Ball.YSpeed; funktioniert auch nicht und YSpeed ist immer noch negativ. |
AW: Problem mit Multiplikation
Zitat:
|
AW: Problem mit Multiplikation
Immer diese Balls. Das Buch ist (sorry) kakke. Mach aus dem Single ein integer. Dann klappt auch die Abfrage.
|
AW: Problem mit Multiplikation
Momentchen, du hast ein "fYSpeed", benutzt in deinem Code aber immer nur "Ball.YSpeed". Wo kommt jetzt dieses fYSpeed ins Spiel?
|
AW: Problem mit Multiplikation
@Bjoerk
Weiß zwar nicht von welchem Buch du redest aber der Quellcode ist nur von mir selbst^^. Liegt es am Single das es nicht funktioniert, weil ich nämlich einen Float Wert bräuchte, deswegen ist es mit Integer nicht möglich. @Medium Ball.fYSpeed und fYSpeed sind dasselbe, war nur zu faul Ball. zu schreiben, sorry falls dich das verwirrt hat. |
AW: Problem mit Multiplikation
Du hattest jedoch "Ball.YSpeed", nicht "Ball.fYSpeed" geschrieben. Solche Kleinigkeiten sind verflucht wichtig. Nicht nur im Code selbst, sondern auch, wenn man darüber spricht/schreibt. Das Beste ist es, wenn du einfach direkt die jeweiligen Stellen in Delphi markiertst und in deinen Beitrag kopierst. Spart die die lästige Schreibarbeit, und deine potenziellen Helfer haben eine Chance tatsächlich hilfreich zu werden.
So wie es jetzt alles da steht, gibt es überhaupt keinen Grund, dass die Vorzeicheumkehrung mittels "*-1" nicht gehen sollte. Und ich kann aus eigener Erfahrung für eine Palette an Delphi-Versionen bestätigen, dass es das stets problemlos konnte. (Es wäre sicherlich auch schon ein wenig aufgefallen wenn nicht.) Also muss an deinem restlichen Code etwas sein, was hier in die Suppe spuckt. (Ich habe ja vorsichtig eine Verquickung von Properties mit Records unter Verdacht, aber ohne deinen tatsächlichen Code gibt es einfach keine Grundlage hier weiter zu machen.) |
AW: Problem mit Multiplikation
So, habe dann die ganzen wichtigen Bereiche in dem Ball vorkommt kopiert
die Klasse: unit uBall; interface type TBall = Class private fXSpeed : Single; fYSpeed : Single; public Constructor Create(xspeed, yspeed : Single); property YSpeed: Single read fYSpeed write fYSpeed; property XSpeed: Single read fXSpeed write fXSpeed; implementation constructor TBall.Create(xspeed, yspeed : Single); begin self.fXSpeed := xspeed; self.fYSpeed := yspeed; end; end; hier wird der ball erzeugt: Ball: TBall; TBall.Create(0,-1) und hier die betreffende methode die nicht funktioniert, in dem fall war Edge=1: procedure TBrick.onCollision(Edge : Integer; Ball : TBall); begin case Edge of 1: Ball.YSpeed := Ball.YSpeed * -1; 2: Ball.YSpeed := Ball.YSpeed * -1; 3: Ball.XSpeed := Ball.XSpeed * -1; 4: Ball.XSpeed := Ball.XSpeed * -1; end; end; Der Auruf ist: Brick.OnCollision(1,Ball); |
AW: Problem mit Multiplikation
Sei doch so gut und setze deinen Code in Delphi Tags, damit die Formatierung (sofern eine vorhanden) beibehalten bleibt. Das ist der Delphi-Helm in der Mitte von den Editor-Symbolen.
Dan sieht dein Quellcode nämlich so aus:
Delphi-Quellcode:
procedure TForm1.Testprocedure;
begin ShowMessage('Delphi TagsTest'); end; |
AW: Problem mit Multiplikation
Zitat:
Delphi-Quellcode:
Wieso funktioniert dein Beispiel nicht?
procedure TForm1.Button1Click(Sender: TObject);
Var Zahl : Single; S : String; begin S := Label1.Caption; Zahl := StrToFloat(S); Zahl := Zahl * -1; S := FloatToStr(Zahl); Label1.Caption := S; end; |
AW: Problem mit Multiplikation
Zitat:
In deinem Code muß es aber heißen:
Delphi-Quellcode:
Ball := TBall.Create(0,-1);
|
AW: Problem mit Multiplikation
Ob nun Integer oder Float macht doch hier überhaupt keinen Unterschied. Es wird ja nirgends ein Vergleich mit Konstanten gemacht, sondern nur gerechnet. Leider ist das noch immer ein wenig wenig Code. Es ist z.B. nicht ersichtlich, in welchem Scope sich die Variable "Ball" befindet, und beim fehlenden "end;" der Klassendeklaration hoffe ich, dass es wirklich einfach nur nicht mit kopiert wurde. Ich denke Bjoerk liegt schon mal ganz gut, seltsam ist jedoch, dass es bei dir dann keine Zugriffsfehler hagelt. Fazit: Die Erzeugung ist definitiv schon mal ein Fehler, aber leider immer noch zu wenig Kontext.
Zum Schluss noch ein kleiner Tipp. Man kann in case-Statements ganz nett Dinge zusammenfassen:
Delphi-Quellcode:
Ist Kosmetik, reduziert aber Arbeit bei Änderungen :)
procedure TBrick.onCollision(Edge: Integer; Ball: TBall);
begin case Edge of 1, 2: Ball.YSpeed := Ball.YSpeed * -1; 3, 4: Ball.XSpeed := Ball.XSpeed * -1; end; end; |
AW: Problem mit Multiplikation
So habe jetzt einige Umschichtungen bei meinem Code vorgenommen, das hat das Problem aber leider nicht gelöst, aber dafür ist er jetzt etwas übersichtlicher. Habe jetzt mal meine ganzen Units bis auf ein paar unwichtige Kommentare etc. reinkopiert. Wenn ich ein Integer statt Single verwende funktioniert es übrigens auch nicht.
Nochmal vielen Dank für die bisherigen Vorschläge.
Delphi-Quellcode:
unit ufrmBreakout;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, uCoords, uBrick, UPaddle, UBall; type TfrmBreakout = class(TForm) lblTime: TLabel; lblScore: TLabel; ptbGame: TPaintBox; TmrGame: TTimer; procedure FormCreate(Sender: TObject); procedure TimerTick(Sender: TObject); private bricks : TList; paddle : TPaddle; balls : TList; end; const BrickColumn = 8; BrickRows = 5; PaddleStartX = 192; PaddleStartY = 380; BallStartAngle = 90; var frmBreakout: TfrmBreakout; implementation {$R *.dfm} procedure TfrmBreakout.FormCreate(Sender: TObject); var Coords: TCoords; Brick: TBrick; x,y: Integer; xBall, yBall : Integer; begin //create the bricks bricks := TList.Create; for x := 0 to (BrickColumn-1) do begin for y := 0 to (BrickRows-1) do begin Coords := TCoords.Create(x*uBrick.BrickWidth,y*uBrick.BrickHeight); Brick := TBrick.Create(Coords); bricks.Add(Brick); end; end; //create the paddle Coords := TCoords.Create(PaddleStartX,PaddleStartY); paddle := TPaddle.Create(Coords); //create the ball xBall := PaddleStartX + (uPaddle.PaddleWidth div 2); yBall := PaddleStartY - UBall.BallRadius; Coords := TCoords.Create(xBall,yBall); balls := TList.Create; balls.Add(TBall.Create(Coords,BallStartAngle,0,-1)); end; procedure TfrmBreakout.TimerTick(Sender: TObject); var i, j : Integer; Ball: TBall; Brick: TBrick; begin for i := 0 to balls.Count-1 do begin Ball := balls[i]; for j := 0 to bricks.Count-1 do begin Brick := bricks[j]; Brick.Collide(Ball); end; Ball.Coords.X := Ball.Coords.X+round(Ball.XSpeed); Ball.Coords.Y := Ball.Coords.Y+round(Ball.YSpeed); lblScore.Caption := 'y: ' + FloatToStr(Ball.YSpeed); end; end; end.
Delphi-Quellcode:
unit uBrick;
interface uses uCoords, uBall; const BrickHeight = 32; BrickWidth = 64; type TBrick = Class private fCoords : TCoords; public Constructor Create(coords: TCoords); Destructor Destroy(); override; property Coords: TCoords read fCoords; procedure Collide(Ball: TBall); procedure onCollision(Edge: Integer; Ball: TBall); function RightX : Integer; function BottomY : Integer; end; implementation constructor TBrick.Create(coords: TCoords); begin self.fCoords := coords; end; destructor TBrick.Destroy; begin fCoords.Destroy(); inherited; end; function TBrick.RightX() : Integer; begin Result := (self.fCoords.X + BrickWidth); end; function TBrick.BottomY() : Integer; begin Result := (self.fCoords.Y + BrickHeight); end; procedure TBrick.Collide(Ball: TBall); begin if (Ball.Coords.X <= self.RightX()) and (Ball.Coords.X >= self.fCoords.X) and (Ball.Coords.Y = self.BottomY()) then begin OnCollision(1,Ball); end else if (Ball.Coords.X <= self.RightX()) and (Ball.Coords.X >= self.fCoords.X) and (Ball.Coords.Y = self.fCoords.Y) then begin OnCollision(2,Ball); end else if (Ball.Coords.Y <= self.BottomY()) and (Ball.Coords.Y >= self.fCoords.Y) and (Ball.Coords.X = self.fCoords.X) then begin OnCollision(3,Ball); end else if (Ball.Coords.Y <= self.BottomY()) and (Ball.Coords.Y >= self.fCoords.Y) and (Ball.Coords.X = self.RightX()) then begin OnCollision(4,Ball); end; end; procedure TBrick.onCollision(Edge : Integer; Ball : TBall); begin case Edge of 1: Ball.YSpeed := Ball.YSpeed * (-1); 2: Ball.YSpeed := Ball.YSpeed * (-1); 3: Ball.XSpeed := Ball.XSpeed * (-1); 4: Ball.XSpeed := Ball.XSpeed * (-1); end; end; end.
Delphi-Quellcode:
unit uBall;
interface uses uCoords, uCalculate; const BallRadius = 8; type TBall = Class private fCoords : TCoords; fDestCoords : TCoords; fAngle : Integer; fXSpeed : Single; fYSpeed : Single; public Constructor Create(coords: TCoords; angle: Integer; xspeed, yspeed : Single); Destructor Destroy(); override; property Coords: TCoords read fCoords; property DestCoords: TCoords read fDestCoords; property XSpeed: Single read fXSpeed write fXSpeed; property YSpeed: Single read fYSpeed write fYSpeed; end; implementation constructor TBall.Create(coords: TCoords; angle : Integer; xspeed, yspeed : Single); begin self.fCoords := coords; self.fAngle := angle; self.fXSpeed := xspeed; self.fYSpeed := yspeed; end; destructor TBall.Destroy; begin fCoords.Destroy(); inherited; end; end.
Delphi-Quellcode:
unit uCoords;
interface type TCoords = Class private fx : Integer; fy : Integer; public Constructor Create(x,y: Integer); Destructor Destroy(); override; property X: Integer read fx write fx; property Y: Integer read fy write fy; end; implementation constructor TCoords.Create(x,y: Integer); begin self.fx := x; self.fy := y; end; destructor TCoords.Destroy; begin inherited; end; end. |
AW: Problem mit Multiplikation
Hallo,
Dein Problem ist sicher nicht die Multiplikation; die arbeitet - wie schon gezeigt - korrekt. Das kannst Du auch leicht sehen, dazu musst Du nur Deinen Timercode etwas abändern:
Delphi-Quellcode:
Dann steht da auch irgendwann eine 1 - anstatt einer -1.
procedure TfrmBreakout.TimerTick(Sender: TObject);
var i, j : Integer; Ball: TBall; Brick: TBrick; begin for i := 0 to balls.Count-1 do begin Ball := balls[i]; for j := 0 to bricks.Count-1 do begin Brick := bricks[j]; Brick.Collide(Ball); lblScore.Caption := 'y: ' + FloatToStr(Ball.YSpeed); Application.ProcessMessages end; Ball.Coords.X := Ball.Coords.X+round(Ball.XSpeed); Ball.Coords.Y := Ball.Coords.Y+round(Ball.YSpeed); end; end; Gruß |
AW: Problem mit Multiplikation
Ich bin mir nicht sicher, hab grad keine IDE zum testen da, aber das da sieht für mich aus wie Durchfall:
Delphi-Quellcode:
Also in Java zumindest wird ohne ein break zwischendrin 1: und 2: (und 3: und 4: ) ausgeführt, was dann zur Folge hätte, dass es wieder das selbe Ergebnis wie davor ist.
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin case Edge of 1: Ball.YSpeed := Ball.YSpeed * (-1); 2: Ball.YSpeed := Ball.YSpeed * (-1); 3: Ball.XSpeed := Ball.XSpeed * (-1); 4: Ball.XSpeed := Ball.XSpeed * (-1); end; end; Oder gabs das in Delphi garnicht? |
AW: Problem mit Multiplikation
Nope, das ist schon richtig so.
|
AW: Problem mit Multiplikation
Zitat:
![]()
Delphi-Quellcode:
case x of
0..2 : y := -1; 1..3 : y := +1; end; |
AW: Problem mit Multiplikation
Zitat:
Das ist einer der größten Designfehler in C/C++/Java/PHP meiner Meinung nach... Wann braucht man das Fallthrough schon mal? Einmal in hundert Jahren? Und wie oft vergisst man auf der anderen Seite einfach ein break und hat einen schwer zu findenden Bug? Aber die Vermutung, dass der Code irgendwie doppelt ausgeführt wird, ist naheliegend. Ich habe in der Vergangenheit auch die Erfahrung gemacht, dass es keine gute Kollisionsbehandlungs-Strategie ist, einfach blind die Geschwindigkeit zu negieren... nicht immer hebt sich die Negation auf wie hier, aber manchmal passiert es auch, dass ein Objekt an einer Kante kleben bleibt, weil ein Simulationsschritt nicht ausreicht, dass es das Objekt, mit dem es kollidiert, wieder verlässt, und so kehrt sich mit jedem Frame das Vorzeichen um und es bewegt sich effektiv gar nicht mehr. Problematisch sind auch Kollisionen mit mehreren Objekten gleichzeitig (könnt hier auch die Ursache sein). Setz mal einen Breakpoint auf deine Kollisionsbehandlung, dann siehst du wahrscheinlich, was Sache ist. |
AW: Problem mit Multiplikation
OK, danke für die Aufklärung :D ich mach viel zu wenig Delphi in letzter Zeit :(
Nächste Frage: kommt das Programm in die onColission? Aufrufe sind zwar da, aber falls die if's nie true sind wird's halt nix. Gerade die letzte Bedingung (Ball.Coords.Y=Self.fCoords.Y) könnte durchaus problematisch sein. |
AW: Problem mit Multiplikation
OT:
Zitat:
Aber zurück zum Thema :mrgreen: |
AW: Problem mit Multiplikation
OT:
Zitat:
|
AW: Problem mit Multiplikation
Vielen Dank für die vielen Ratschläge aber leider besteht das Problem weiterhin.
Die Bedingung für OnCollision stimmt auf jeden Fall und er kommt auch bis zum Case.
Delphi-Quellcode:
wenn ich zb. Ball.YSpeed := 1; setze funktioniert es einwandfrei und es erreicht den Effekt den ich eigentlich mit *(-1) erreichen wollte.
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin case Edge of 1: Ball.YSpeed := Ball.YSpeed * (-1); 2: Ball.YSpeed := Ball.YSpeed * (-1); 3: Ball.XSpeed := Ball.XSpeed * (-1); 4: Ball.XSpeed := Ball.XSpeed * (-1); end; end;
Delphi-Quellcode:
Und Ball.YSpeed ist in diesem fall auch 100% -1 weil folgendes auch funktioniert:
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin case Edge of 1: Ball.YSpeed := 1; 2: Ball.YSpeed := Ball.YSpeed * (-1); 3: Ball.XSpeed := Ball.XSpeed * (-1); 4: Ball.XSpeed := Ball.XSpeed * (-1); end; end;
Delphi-Quellcode:
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin if Ball.YSpeed = -1 then Ball.YSpeed := 1; end; |
AW: Problem mit Multiplikation
Ok konnte das Problem jetzt eingrenzen:
Delphi-Quellcode:
ergibt das Ball.YSpeed = 1 ist.
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin if Ball.YSpeed = -1 then begin Ball.YSpeed := Ball.YSpeed * (-1); end; end;
Delphi-Quellcode:
ergibt das Ball.YSpeed = 1 ist.
if Ball.YSpeed = -1 then
begin Ball.YSpeed := Ball.YSpeed + 2; end;
Delphi-Quellcode:
ergibt das Ball.YSpeed = -1 bleibt
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin if Edge = 1 then begin Ball.YSpeed := Ball.YSpeed * (-1); end; end;
Delphi-Quellcode:
ergibt das Ball.YSpeed = 3 ist. Anscheinend wird onCollision 2mal hintereinander aufgerufen. Warum das so ist muss ich aber noch herausfinden
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
begin if Edge = 1 then begin Ball.YSpeed := Ball.YSpeed + 2; end; end; |
AW: Problem mit Multiplikation
Ich vermute gaaaaaaaaanz stark, dass es in dem Scope der Methode noch ein "Edge" gibt, dass höhere Priorität als der Parameter hat. Weil es geht immer nur dann gut, wenn du "Edge" gerade eben nicht als Bedingung benutzt. Benenne den Parameter doch mal spaßeshalbar um, z.B. nach "aEdge", das wäre sogar noch styleguidekonform :)
Edit: Oder ggf. auch "Ball" mal nach "aBall" umbenennen, auch hier könnte ein ähnliches Problem sein. Hast du z.B. globale Variablen mit diesen Namen? |
AW: Problem mit Multiplikation
Hallo,
so wie ich das sehe, ist das Problem hier:
Delphi-Quellcode:
.
procedure TBrick.onCollision(Edge : Integer; Ball : TBall);
Wenn "Ball" geändert werden soll, dann muss es lauten:
Delphi-Quellcode:
.
procedure TBrick.onCollision(Edge : Integer;var Ball : TBall);
Ansonsten wird Ball nicht verändert (ohne var kein "call by reference"). Hier mal ein Beispiel:
Delphi-Quellcode:
Ergibt:
procedure var_minus(var i: Integer);
begin i := i * -1; end; procedure minus(i: Integer); begin i := i * -1; end; procedure TForm3.Button1Click(Sender: TObject); var i: Integer; j: Integer; begin i := 1; j := 1; minus(i); var_minus(j); Label1.Caption := Format('i: %d, j: %d', [i, j]); end;
Code:
i: 1, j: -1
|
AW: Problem mit Multiplikation
Objekte werden immer als Referenz übergeben, deshalb ist "var" hier überflüssig.
|
AW: Problem mit Multiplikation
Zitat:
|
AW: Problem mit Multiplikation
Zitat:
|
AW: Problem mit Multiplikation
Gegenvorschlag? Ich bin zwar auch der Meinung, dass Parameter im Scope der Methode höchstens noch von lokalen Variablen überdeckt würden (aber das meckert Delphi ja auch an), nur etwas anderes sehe ich einfach nicht, und es fällt schon auf, dass sobald mittels "Edge" verzweigt wird, die Vorzeichenumkehrung nicht erreicht wird. Da es Klassen sind dürfte auch Copy-on-Write hier nicht zuschlagen, was ganz am Anfang mein Gedanke war.
Edit: Nope, stimmt. Habe das Detail mit "jetzt ist es 3" übersehen. Gut, dann passiert da etwas doppelt, hast mich überredet ;) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz