BPS #3: Verfolgungswahn - Auswertung

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

Xeres

Moderator

Betreff: BPS #3: Verfolgungswahn - Auswertung

BeitragMo, Feb 28, 2011 20:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Uuund Aus!

Das war die Aufgabe

Postet hier eure Ergebnisse, Codes, Gedanken. Lernt von den anderen, seht euch deren Quelltext an und versucht euren eigenen zu verbessern.

Diskussion
Postet zu euren Codes stets eine kurze Erklärung mit euren Gedanken in denen ihr simpel gesagt die Frage "Wieso habe ich XY auf diese Art gelöst?" beantwortet. Beiträge, die nur den Code enthalten werden wir aus dem Thread entfernen.

Nächste Aufgabe
In drei Tagen, am 3. März wird die Musterlösung nach editiert und die nächste Aufgabe eingestellt.

Viel Spaß & viel Erfolg!

Musterlösung:
BlitzMax: [AUSKLAPPEN]
SuperStrict
SeedRnd(MilliSecs())
Const gfx_w:Int = 500, gfx_h:Int = 500

Graphics(gfx_w, gfx_h)
Local FrameTimer:TTimer = TTimer.Create(60)
HideMouse()

'* Konstanten erhöhen die Lesbarkeit!
Const eyes_size:Int = 48

'* Mauskoordinaten:
Global mh1:Int, mx:Int, my:Int

'* Augenpaar gut sichtbar innerhalb des Fensters anzeigen:
Local eyes_x:Int = Rand(gfx_w * 0.2, gfx_w * 0.8)
Local eyes_y:Int = Rand(gfx_h * 0.2, gfx_h * 0.8)
Local eyes_angle:Int '* Da wird die Richtung gespeichert, in die die Augen gucken.

Repeat
Cls
'* Oft benutzte Werte am besten zwischenspeichern!
mx = MouseX()
my = MouseY()

'* Obacht! Atan2 Erwartet als ersen Paramter Y nicht X!
'* hier gilt: Ziel - Start
'* Das Negative Vorzeichen sorgt für die Mathematisch korrekte
'* Drehrichtung des Winkels (gegen den Uhrzeigersinn)
'* (...+360) mod 360 gibt a) einen Positiven Winkel der b) im Bereich 0-359 liegt.
eyes_angle = (-ATan2(my - eyes_y, mx - eyes_x) + 360) Mod 360

'* Der Berechnete Winkel wird beim Zeichnen der Augen verwendet:
DrawEyes(eyes_x, eyes_y, eyes_size, eyes_angle)

'* Maus Zeichnen:
SetColor(0, 200, 0)
DrawCircle(mx, my, 16)

Flip(0)
FrameTimer.Wait()
Until KeyHit(KEY_ESCAPE)

Function DrawEyes(x:Int, y:Int, size:Int, angle:Int)
SetColor(255, 255, 255) '* Farbe: Weiß
DrawCircle(x - size / 2, y, size) '* Linkes Auge
DrawCircle(x + size / 2, y, size) '* Rechtes Auge
SetColor(0, 0, 0) '* Farbe: Schwarz
'* Rechte und Linke Puppille:
DrawCircle(x - size / 2 + Cos(angle) * size / 4, y - Sin(angle) * size / 4, size / 4)
DrawCircle(x + size / 2 + Cos(angle) * size / 4, y - Sin(angle) * size / 4, size / 4)
'* x - size / 2 + Cos(angle) * size / 4 =>
'* x - size / 2 = Mittelpunkt des Linken Auges
'* + Cos(angle) * size / 4 = Verschiebung in Richtung des Winkels um den Wert size / 4
End Function

Function DrawCircle(x:Int, y:Int, r:Int)
'* Der Mittelpunkt des Kreises liegt bei x, y.
DrawOval(x - r / 2, y - r / 2, r, r)
End Function
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
  • Zuletzt bearbeitet von Xeres am Do, März 03, 2011 23:05, insgesamt einmal bearbeitet

skey-z

BeitragMo, Feb 28, 2011 23:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Hätte es fast vergessen, mal eben auf die schnelle was auf die Beine gestellt.

Die herangehensweise:
Auch wenn viele Augen(paare) gezeichnet werden, soll jedes Auge separat auf die Maus blicken.
Demzufolge muss jedes Auge als Objekt erstellt werden und mit ATan2 der winkel zur Mausposition berechnet werden.
Für jedes Auge wird der Hintergrund(weiß), eine vordefinierte Augenfarbe(blau, braun, grün, blau-grau) und eine Iris(schwarz) gezeichnet.
Durch die einzelnen Augen kann somit auch direkt ein 'schielen' hervorgerufen werden.
Wenn das nicht gewünscht wäre, müsste man jedes Augenpaar als Objekt, anstatt jedes Auge als Objekt betrachten oder den Bezugspunkt jedes Augenpaares zwischenspeichern und diesen mit der Mausposition verarbeiten.

Nun genug der Theorie, den Code habe ich an den wichtigsten Stellen kurz kommentiert
BlitzMax: [AUSKLAPPEN]

Rem

Projekt: BPS#3 - Verfolgungswahn
Autor: skey-z

Beschreibung/Aufgabenstellung:
Programmiert ein Augenpaar, das immer den Mauscursor anguckt.
Ein einzelnes Augenpaar reicht für die Lösung der Aufgabe aus, aber wer das schon geschafft hat,
könnte mittels Types beliebig viele Augen erstellen, oder beliebige andere Verfeinerungen machen (schielen, Augenlieder usw.).

EndRem


SuperStrict


'Jedes Auge ist ein separates Object
Type TEye

'Objektliste und Verknüpfung
Global _eyeList:TList = CreateList()
Field _eyeLink:TLink

'Augenplazierung und Größe
Field _eyeX:Int
Field _eyeY:Int
Field _eyeW:Int
Field _eyeH:Int

'Augenfarbe
Field _colRed:Int = 0
Field _colGreen:Int = 0
Field _colBlue:Int = 0

'Irisplatzierung als Unterobjekt zu den eigentlichen Augen
Field _irisAngle:Double
Field _irisX:Int
Field _irisY:Int
Field _irisSize:Int

'Jedes Auge der Liste hinzufügen
Method New()
_eyeLink = _eyeList.AddLast(Self)
End Method

'Auge erstellen
Method Create(x:Int, y:Int, w:Int, h:Int, color:String="")

'Positions und Größenwerte zuweisen
_eyeX = x
_eyeY = Y
_eyeW = w
_eyeH = h
_irisSize = h*.67 '2/3 der Höhe

'Augenfarbe zuweisen
Select color
Case "blue"
_colBlue = 255
Case "green"
_colGreen = 255
Case "brown"
_colRed = 64
_colGreen = 32
Case "iceblue"
_colRed = 160
_colGreen = 160
_colBlue = 255
Default
_colBlue = 255
End Select
End Method

'Augen verfolgen die Maus
Method Update(mx:Int, my:Int)

'Winkel von Maus zu Augen ausrechenen
'+90 um den Winkel zu korrigieren
_irisAngle = (ATan2((_eyeY-my),(_eyeX-mx))+90) Mod 360

'Winkel für die Augen einstellen
_irisX = -Sin(_irisAngle)*(_eyeW/5)
_irisY = +Cos(_irisAngle)*(_eyeH/10)
End Method

'Selbsterklärend
Method Draw(mx:Int, my:Int)

'Damit sparen wir in der Hauptschleife einen kompletten Durchlauf der Liste
Self.Update(mx, my)

'Hintergrund malen
SetColor (255,255,255)
DrawOval(_eyeX-(_eyeW/2), _eyeY-(_eyeH/2), _eyeW, _eyeH)

'Augenfarbe
SetColor(_colRed, _colGreen, _colBlue)
DrawOval(_eyeX-(_irisSize/2)+_irisX, _eyeY-(_irisSize/2)+_irisY, _irisSize, _irisSize)

'Iris
SetColor(0,0,0)
DrawOval(_eyeX-(_irisSize/2/2)+_irisX, _eyeY-(_irisSize/2/2)+_irisY, _irisSize/2, _irisSize/2)
End Method

Method Remove()
_eyeLink.Remove()
End Method
End Type



'Fenster initialisieren
Global gWidth:Int = 800
Global gHeight:Int = 600
Graphics gWidth, gHeight

'Variablen Festlegen
Local quit:Byte

'Objekte generieren

For Local y:Int = 1 To 3 Step 2
For Local x:Int = 1 To 3 Step 2
CreateEyePair(gWidth/4*x, gHeight/4*y, 75, 33, "iceblue")
Next
Next

createEyePair(gWidth/2, gHeight/2, 150, 75, "green")


'Hauptschleife
While Not quit

'Input______________________

'Keys
Local kh_esc:Int = KeyHit(KEY_ESCAPE)

'Mouse
Local mx:Int = MouseX()
Local my:Int = MouseY()
'___________________________

'Proceed____________________

'Prüfen ob ESC oder der CloseWindow-Button gedrückt wurde
If kh_esc Or AppTerminate() Then
If Confirm("Quit") Then quit = True
EndIf
'___________________________

'Update_Objects_____________
For Local eyes:TEye = EachIn TEye._eyeList
Next
'___________________________

'Draw_______________________
For Local eyes:TEye = EachIn TEye._eyeList
eyes.Draw(mx, my)
Next
'___________________________

'Update_____________________
Flip
Cls
'___________________________

Wend

For Local eyes:TEye = EachIn TEye._eyeList
eyes.Remove()
Next

GCCollect()

'Ein Augenpaar erstellen
Function CreateEyePair(x:Int, y:Int, w:Int, h:Int, color:String="")

For Local i:Int = -1 To 1 Step 2
Local eye:TEye = New TEye
eye.Create(x+(w*i), y, w, h, color)
Next
End Function
Awards:
Coffee's Monatswettbewerb Feb. 08: 1. Platz
BAC#57: 2. Platz
Twitter

BlitzMoritz

BeitragDi, März 01, 2011 20:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Portierung meines "nicht ganz seriösen" Blitz3D-Spaßbeitrags nach BlitzMax inklusive minib3d-Modul. Wer dieses nicht installieren will oder kann, findet hier die Exe-Demo.
BlitzMax: [AUSKLAPPEN]
Framework sidesign.minib3d
Global LinkeIris, LinkePupille, RechteIris, RechtePupille
Kopf_zusammenbauen()

Repeat 'Ich messe einfach den Abstand zwischen der Maus und der absoluten Bildschirmposition
'der Pupillen und füge noch den vermindernden Korrekturfaktor 0.1 hinzu, das war's.
'Den Rest erledigt die 3D-Funktion 'RotateEntity' Wink
RotateEntity(LinkeIris, 0.1 * (206 - MouseY()), 0.1 * (MouseX() - 306), 0)
RotateEntity(LinkePupille, 0.1 * (206 - MouseY()), 0.1 * (MouseX() - 306), 0)
RotateEntity(RechteIris, 0.1 * (206 - MouseY()), 0.1 * (MouseX() - 494), 0)
RotateEntity(RechtePupille, 0.1 * (206 - MouseY()), 0.1 * (MouseX() - 494), 0)
RenderWorld()
Flip
Until KeyDown(KEY_ESCAPE) Or AppTerminate()

Function Kopf_zusammenbauen()
Graphics3D 800, 600, 0, 2
Local Light = CreateLight(), pivot = CreatePivot(), camera = CreateCamera(pivot)
PositionEntity(camera, 0, 0, -12)
RotateEntity Light, 0, 75, 90
Kopf = CreateSphere(24)
EntityColor(Kopf, 255, 139, 100)
ScaleEntity(Kopf, 6, 8, 1)
EntityShininess(Kopf, 1)
Haare = CreateSphere(24)
EntityColor(Haare, 74, 37, 0)
PositionEntity(Haare, 0, 5, 1)
ScaleEntity(Haare, 6, 4, 1.75)
Nase = CreateCone(24)
EntityColor(Nase, 255, 119, 100)
PositionEntity(Nase, 0, 0, -0.75)
ScaleEntity(Nase, 1.5, 2, 1)
EntityShininess(Nase, 1)
Mund = CreateSphere(24)
EntityColor(Mund, 166, 0, 0)
PositionEntity(Mund, 0, -3.5, -0.9)
ScaleEntity(Mund, 2, 0.25, 0.25)
EntityShininess(Mund, 1)
LinkerAugapfel = CreateSphere(24)
PositionEntity(LinkerAugapfel, -2.25, 2.25, -1.25)
RechterAugapfel = CreateSphere(24)
PositionEntity(RechterAugapfel, 2.25, 2.25, -1.25)
LinkeIris = CreateSphere(24)
EntityColor(LinkeIris, 0, 0, 255)
PositionEntity(LinkeIris, -2.25, 2.25, -1.125)
ScaleEntity(LinkeIris, 0.8, 0.8, 1.25)
EntityShininess(LinkeIris, 1)
RechteIris = CreateSphere(24)
EntityColor(RechteIris, 0, 0, 255)
PositionEntity(RechteIris, 2.25, 2.25, -1.125)
ScaleEntity(RechteIris, 0.8, 0.8, 1.25)
EntityShininess(RechteIris, 1)
LinkePupille = CreateSphere(24)
EntityColor(LinkePupille, 0, 0, 0)
PositionEntity(LinkePupille, -2.25, 2.25, -1.125)
ScaleEntity(LinkePupille, 0.5, 0.5, 1.4)
EntityShininess(LinkePupille, 1)
RechtePupille = CreateSphere(24)
EntityColor(RechtePupille, 0, 0, 0)
PositionEntity(RechtePupille, 2.25, 2.25, -1.125)
ScaleEntity(RechtePupille, 0.5, 0.5, 1.4)
EntityShininess(RechtePupille, 1)
End Function
  • Zuletzt bearbeitet von BlitzMoritz am Di, Mai 31, 2011 20:05, insgesamt einmal bearbeitet

blackgecko

BeitragMi, März 02, 2011 22:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich mach auch mal mit.
Der Code ist schön kommentiert, denke ich.
Es gibt eine Klasse, die sich um einzelne Augen kümmert und eine, die Augenpaare verwaltet, wobei die natürlich auf die andere zugreift.
Vlt noch ein paar Worte zur Hauptsache des Ganzen: Den Pupillen
Ich hab folgendes gemacht: Wenn der Mauszeiger innerhalb der Augen ist, wird die Pupille direkt an den Mauszeiger gezeichnet. Dadurch werden so unschöne Sprung-Effekte wie bei skey-zs Code, wenn man mit der Maus nah am Zentrum herumfährt, vermieden. (nichts für ungut, ist mir nur aufgefallen Wink )Ist der Mauszeiger nun außerhalb des Auges, wird mit Hilfe von Atan2 der Winkel zwischen Augmittelpunkt und Mauszeiger bestimmt und dann mit Sinus und Kosinus berechnet, wohin (innerhalb des Auges) die Pupille gezeichnet wird.
So und nun der Code:
BlitzMax: [AUSKLAPPEN]
SuperStrict
SeedRnd MilliSecs()

'ein einzelnes Auge
Type TEye
Field x:Int
Field y:Int
Field radius:Int
Function Create:TEye(x:Int,y:Int,rad:Int)
Local E:TEye = New TEye
E.x = x
E.y = y
E.radius = rad
Return E
EndFunction
Method draw()
SetColor 255,255,255
DrawOval x,y,radius,radius 'Das Weiße im Auge - das war noch einfach...

Local pupil_x:Int 'Variablen für die X- und Y-Postion
Local pupil_y:Int 'der Pupille
Local pupil_rad:Int = radius/4 'Größe der Pupille

Local m_x:Int = MouseX()
Local m_y:Int = MouseY()

If m_x > x And m_x < x+radius And m_y > y And m_y < y+radius Then 'Wenn der Mauszeiger innerhalb des Auges ist,
pupil_x = m_x 'wird die Pupille direkt dorthin gezeichnet.
pupil_y = m_y 'Das ermöglicht extremes Schielen.
Else 'Wenn er außerhalb ist, wirds kompliziert:
Local mid_x:Int = x + radius/2 'Mitte des
Local mid_y:Int = y + radius/2 'Auges
Local angle:Float = ATan2((m_y-mid_y),(m_x-mid_x)) 'Berechnung des Winkels

Local shift_x:Int = Cos(angle)*(radius/2) 'Trigo-
Local shift_y:Int = Sin(angle)*(radius/2) 'nometrie

pupil_x = mid_x + shift_x
pupil_y = mid_y + shift_y
EndIf

SetColor 0,0,0
DrawOval pupil_x-pupil_rad/2,pupil_y-pupil_rad/2,pupil_rad,pupil_rad
EndMethod
EndType


'Eine Klasse für Augenpaare
Type TEyePair
Global eyepairs:TList = New TList
Field eye1:TEye 'Das erste Auge
Field eye2:TEye 'Das zweite Auge
Field vx:Int
Field vy:Int
Function Create:TEyePair(x:Int=Null,y:Int=Null,radius:Int=20)
If x = Null Then x = Rand(0,GraphicsWidth()-2*radius-5)
If y = Null Then y = Rand(0,GraphicsHeight()-radius)
Local P:TEyepair = New TEyepair
P.eye1 = TEye.Create(x,y,radius)
P.eye2 = TEye.Create(x+radius+5,y,radius)
P.vx = Rand(2,5)
P.vy = Rand(2,5)
eyepairs.addlast(P)
Return P
EndFunction
Function drawall() 'Alle Augenpaare zeichnen
For Local i:TEyePair = EachIn eyepairs
i.draw()
Next
EndFunction
Function moveAll() '...Überraschung
For Local i:TEyePair = EachIn eyepairs
i.move()
Next
EndFunction
Method move() '...Überraschung
eye1.x :+ vx
eye1.y :+ vy
eye2.x :+ vx
eye2.y :+ vy
If eye1.x < 0 Or eye2.x > GraphicsWidth()-eye2.radius Then vx = -vx
If eye1.y < 0 Or eye1.y > GraphicsHeight()-eye1.radius Then vy = -vy
EndMethod
Method draw() 'zeichnen
eye1.draw()
eye2.draw()
EndMethod
EndType


Graphics 640,480,0

'Ich denke 10 Augenpaare sind gruselig genug?
For Local i:Int = 1 To 10
TEyepair.Create(Null,Null,Rand(10,60))
Next


Local tim:TTimer = TTimer.Create(40)
Repeat
tim.wait()
Cls
' TEyepair.moveAll() 'Was wohl passiert wenn man den Kommentarstrich wegmacht? *Pfeif*
TEyepair.drawAll()
Flip
Until AppTerminate() Or KeyHit(KEY_ESCAPE)



Und wem das jetzt noch nicht reicht, der kann ja mal versuchen, in der Hauptschleife den Kommentar-Apostroph zu entfernen Wink
PS: Ich hab gemerkt, dass ich die zahlreichen Durchmesser-Variablen fälschlicherweise als 'Radius' bezeichnet habe. Embarassed
So long and thanks for all the fish.
Fedora 17 | Windows 7 || BlitzPlus | BlitzMax
Rechtschreibflame GO!!! Deppenapostroph | SeidSeit | Deppenakzent | DassDas | Deppenleerzeichen | TodTot | enzigste.info - Ja, ich sammel die.

Xeres

Moderator

BeitragDo, März 03, 2011 23:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Besten Dank an alle bisherigen Teilnehmer.

Die Musterlösung findet sich im Eingangspost.

Fragen & Anregungen sind und bleiben erwünscht Wink

@blackgecko:
Ich wusste ehrlich nicht, dass Null mit Integer-Variablen funktioniert - ich hätte den "Illegal type conversion" Error erwartet.
BlitzMax: [AUSKLAPPEN]
Local x:Int = Null

cool.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

amon

BeitragSo, März 06, 2011 15:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Spät aber doch, es geht auch ohne Trigonometrie, dafür mit Vektoren:

BlitzMax: [AUSKLAPPEN]

SuperStrict

Type TFace

Field leftEye:TEye
Field rightEye:TEye

Function Create:TFace(center:TPos2D)
Local t:TFace = New TFace
Local leftCenter:TPos2D = TPos2D.Create(center.x - 40, center.y)
Local rightCenter:TPos2D = TPos2D.Create(center.x + 40, center.y)
t.leftEye = TEye.Create(leftCenter)
t.rightEye = TEye.Create(rightCenter)
Return t
EndFunction

Method Draw()
leftEye.Draw()
rightEye.Draw()
EndMethod

Method LookAt(pos:TPos2D)
leftEye.LookAt(pos)
rightEye.LookAt(pos)
EndMethod

EndType

Type TEye

Field eye:TPos2D
Field pupil:TPos2D

Function Create:TEye(center:TPos2D)
Local t:TEye = New TEye
t.eye.x = center.x
t.eye.y = center.y
Return t
EndFunction

Method New()
eye = New TPos2D
pupil = New TPos2D
EndMethod

Method Draw()
SetColor 255,255,255
DrawOval eye.x - 20.0, eye.y - 20.0, 40.0, 40.0
SetColor 120,120,255
DrawOval pupil.x - 5.0, pupil.y - 5.0, 10.0, 10.0
EndMethod

Method LookAt(pos:TPos2D)
Local lookvec:Vec2D = Vec2D.Create(pos.x, pos.y)
lookvec = lookvec.Sub(Vec2D.Create(eye.x, eye.y))
Local eyevec:Vec2D = lookvec.Normalize().Mul(10.0*lookvec.Length())
If eyevec.Length() > 10
eyevec = lookvec.Normalize().Mul(10)
End If

pupil.x = eye.x + eyevec.x
pupil.y = eye.y + eyevec.y
EndMethod

EndType

Type TPos2D
Field x:Double
Field y:Double

Function Create:TPos2D(x:Double, y:Double)
Local t:TPos2D = New TPos2D
t.x = x
t.y = y
Return t
EndFunction

EndType

Type Vec2D
Field x:Double
Field y:Double

Function Create:Vec2D(x:Double, y:Double)
Local t:Vec2D = New Vec2D
t.x = x
t.y = y
Return t
EndFunction

Method Add:Vec2D(other:Vec2D)
Local t:Vec2D = New Vec2D
t.x = x + other.x
t.y = y + other.y
Return t
EndMethod

Method Sub:Vec2D(other:Vec2D)
Local t:Vec2D = New Vec2D
t.x = x - other.x
t.y = y - other.y
Return t
EndMethod

Method Normalize:Vec2D()
Local n:Double = 1 / Self.Length()
Local t:Vec2D = Self.Mul(n)
Return t
EndMethod

Method Length:Double()
Return Sqr(x*x+y*y)
EndMethod

Method Mul:Vec2D(skalar:Double)
Local t:Vec2D = New Vec2D
t.x = x * skalar
t.y = y * skalar
Return t
EndMethod

EndType

Graphics 800,600

Local cx:Double = 400.0
Local cy:Double = 300.0
Local mx:Double
Local my:Double

Local center:TPos2D = TPos2D.Create(cx, cy)
Local center2:TPos2D = TPos2D.Create(100, 50)

Local face:TFace = TFace.Create(center)
Local face2:TFace = TFace.Create(center2)




While Not AppTerminate()

Cls

mx = MouseX()
my = MouseY()

Local lookAtPos:TPos2D = TPos2D.Create(mx, my)

Plot MouseX(), MouseY()

face.LookAt(lookAtPos)
face.Draw()

face2.LookAt(lookAtPos)
face2.Draw()

Flip

Wend




Es ist sicher noch etwas Optimierungsbedarf da, aber zu kompliziert wollte ich es auch nicht werden lassen.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group