+ All Categories
Home > Documents > Memorial University of Newfoundlandav/courses/5895-current/manual_uploads/...import android...

Memorial University of Newfoundlandav/courses/5895-current/manual_uploads/...import android...

Date post: 05-Feb-2021
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
12
Graphics with libGDX Dr. Andrew Vardy Adapted from the following sources: libGDX slides by Jussi Pohjolainen (Tampere Unversity of Applied Sciences) transformation slides by Dr. Paul Gillard (Memorial University) ENGI 5895 Software Design Memorial University Introduction The goal here is to illustrate some concepts in computer graphics The tool we will use is libGDX, a cross-platform game development environment libGDX library provides six interfaces to abstract away platform details Application, Files, Input, Net, Audio, Graphics The graphics library wraps OpenGL ES or WebGL OpenGL has emerged as a standard library for graphics; ES = Embedded Systems OpenGL ES available on Android and iOS WebGL is a Javascript API that conforms to OpenGL ES Cross-platform libGDX targets Desktop, Android, HTML5, and iOS Desktop via LWJGL (Lightweight Java Game Library) Android via Android SDK HTML5 via GWT (Google Web Toolkit) Java -> Javascript iOS via RoboVM Java -> Objective-C For an alternate intro to libGDX try “2D Game Development with libGDX” from Udacity interface Application According to the libGDX API: “An Application is the main entry point of your project. It sets up a window and rendering surface and manages the different aspects of your application, namely Graphics, Audio, Input and Files. Think of an Application being equivalent to Swing's JFrame or Android's Activity.” Application is an interface which is implemented by one of the following: JglfwApplication (Desktop) AndroidApplication (Android) GwtApplication (HTML5) IOSApplication (iOS)
Transcript
  • GraphicswithlibGDXDr.AndrewVardy

    Adaptedfromthefollowingsources:libGDX slides byJussi Pohjolainen (TampereUnversity ofAppliedSciences)

    transformationslidesbyDr.PaulGillard(MemorialUniversity)

    ENGI5895SoftwareDesign

    MemorialUniversity

    Introduction

    • Thegoalhereistoillustratesomeconceptsincomputergraphics• ThetoolwewilluseislibGDX,across-platformgamedevelopmentenvironment• libGDX libraryprovidessixinterfacestoabstractawayplatformdetails

    • Application,Files,Input,Net,Audio,Graphics• ThegraphicslibrarywrapsOpenGLESorWebGL

    • OpenGLhasemergedasastandardlibraryforgraphics;ES=EmbeddedSystems• OpenGLESavailableonAndroidandiOS• WebGL isaJavascript APIthatconformstoOpenGLES

    Cross-platform

    • libGDX targetsDesktop,Android,HTML5,andiOS• DesktopviaLWJGL(LightweightJavaGameLibrary)• AndroidviaAndroidSDK• HTML5viaGWT(GoogleWebToolkit)

    • Java->Javascript• iOSviaRoboVM

    • Java->Objective-C

    • ForanalternateintrotolibGDX try“2DGameDevelopmentwithlibGDX”fromUdacity

    interfaceApplication

    • AccordingtothelibGDX API:

    “AnApplicationisthemainentrypointofyourproject.Itsetsupawindowandrenderingsurfaceandmanagesthedifferentaspectsofyourapplication,namelyGraphics,Audio,InputandFiles.ThinkofanApplicationbeingequivalenttoSwing'sJFrame orAndroid'sActivity.”

    • Applicationisaninterfacewhichisimplementedbyoneofthefollowing:• JglfwApplication (Desktop)• AndroidApplication (Android)• GwtApplication (HTML5)• IOSApplication (iOS)

  • • TheApplicationinterfaceandthecorrespondingXXXApplication (e.g.AndroidApplication)classesexistanddon’tneedtobemodified• CreateyourownappbyimplementingApplicationListener

    App(Lifecycle(

    Thisiswhatyouhavetoimplementtomakeyourowngame/app

  • ListenersandAdapters(JavaConcept)

    • Usuallya“Listener”inJavarespondstoevents• e.g.inSwinginterfaceMouseListener definesthefollowingmethods:

    mouseClicked,mouseEntered,mouseExited,mousePressed,mouseReleased

    • ThisisreallyjustanotherflavouroftheObserverpattern• Butwhatifyouonlycareabout“mouseClicked”events?YourconcreteListenerhastodefineall5ofthemethodsabove• ToavoidthistheabstractclassMouseAdapter isdefinedwhichprovidesemptymethodsforallofthese• NowyourconcreteListenercanextendMouseAdapter insteadofimplementingMouseListener andyoudefineonlythemethodsyouwant

    About(Starter(Classes(

    •  For(each&plaVorm&(iOS,(Android,(Desktop(..)(a(starter(class(must(be(wri_en(

    •  Starter(classes(are(plaTorm(dependent(•  We(will(focus(on((– Desktop((LWJGL)(– Android&

    Starter(Classes:(Desktop(// This is platform specific: Java SEpublic class DesktopStarter { public static void main(String[] argv) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.title = “…”; config.width = 480; config.heigth = 320; new LwjglApplication(new MyGame(), config); }}

  • Starter(Classes:(Android(import android.os.Bundle;import com.badlogic.gdx.backends.android.AndroidApplication;import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;

    // This is platform specific: Android// No mainpublic class AndroidLauncher extends AndroidApplication { @Override protected void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); MyGame game = new MyGame(); initialize(game, config); if(this.getApplicationListener() == game) { this.log("test", "success"); } }}

    Android(Manifest(

    Android(Permissions(

    •  Add(permissions(if(your(android(app(requires(certain(funcAonality(–  – 

    – 

    •  Add(these(to(manifest(file •  See(–  http://developer.android.com/guide/topics/manifest/manifest-intro.html#perms

    ProjectSetup

    • RatherthancraftyourownStarterClasses,Irecommendusingtheprojectgenerator(gdx-setup.jar)referredtohere:• https://github.com/libgdx/libgdx/wiki/Project-Setup-Gradle

    • Torunonthedesktop:• ClickRun->“EditConfigurations...”• Click”+”inupper-leftcorner• Select“Gradle”(thebuildsystem)

    • Change“Name”toDesktop• Set“Tasks”todesktop:run

    • With“Desktop”selected,hittheplaybutton• Ifeverythingworks,thisshouldappear:

  • • Thefollowingclasswillbedefinedincore/src/com.mygdx.game

    publicclassMyGdxGame extendsApplicationAdapter {SpriteBatchbatch;Textureimg;

    @Overridepublicvoidcreate(){batch=newSpriteBatch();img =newTexture("badlogic.jpg");

    }

    @Overridepublicvoidrender(){Gdx.gl.glClearColor(1,0,0,1);Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);batch.begin();batch.draw(img,0,0);batch.end();

    }

    @Overridepublicvoiddispose(){batch.dispose();img.dispose();

    }}

    Locatedinandroid/assets(otherplatforms linktothisdir)

    TwolinesofactualOpenGL;Colour specifiedasred,green,blue,alpha(opacity)

    Entities(hereanimage)drawninabatchtooptimize themforprocessingbytheGPU

    Isn’tJavasupposed tohavegarbagecollection(GC)? Unfortunately,GCisunpredictableandcostly.Iflargeresources(e.g.images)weresubjecttoGCitcouldcausegamelag.Also,objectsallocatedoutside theJVM(e.g.bycallingC++code)arenotGC’d.

    Example:“ASimpleGame”

    • Thisexamplewasadaptedfrom

    https://github.com/libgdx/libgdx/wiki/A-simple-game

    • Asimplezen-likegamewithnoend:• Catchraindropswithabucketonthebottomofthescreen.• Raindropsspawnrandomlyatthetopofthescreeneverysecondandacceleratedownwards.

    • Playerdragsthebuckethorizontallyviathemouse/touchorbythekeyboardusingleftandrightcursorkeys.

    packagecom.mygdx.game;

    import/*NOTSHOWN*/

    publicclassDropextendsApplicationAdapter {privateTexturedropImage;privateTexturebucketImage;privateSpriteBatch batch;privateOrthographicCamera camera;privateSpritebucket;privateArrayraindrops;privatelonglastDropTime;

    //Thewidthandheightofthescreen--- assumednot//tochange(otherwisedefineresize).privateint width,height;

    ...

    Imagestobeloadedfromfiles

    Havingacameraenablesmanipulating theviewindependent oftheworld.Twochoices:- PerspectiveCamera:Distantobjectswillappear

    smaller.Good for3D.- OrthographicCamera:Thesceneisprojected

    ontoaplane.Good for2D.

    @Overridepublicvoidcreate(){//loadtheimagesforthedropletandthebucket,64x64pixelseachdropImage =newTexture(Gdx.files.internal("droplet.png"));bucketImage =newTexture(Gdx.files.internal("bucket.png"));

    width=Gdx.graphics.getWidth();height=Gdx.graphics.getHeight();

    //createthecameraandtheSpriteBatchcamera=newOrthographicCamera();camera.setToOrtho(false,width,height);batch=newSpriteBatch();

    //createaSpritetologically representthebucketbucket=newSprite(bucketImage);bucket.setX(width/2- bucket.getWidth()/2);//centerthebuckethorizontallybucket.setY(20);//bottomleftcornerofthebucketis20pixelsabovethebottomscreenedge

    //createtheraindropsarrayandspawnthefirstraindropraindrops=newArray();spawnRaindrop();

    }

  • privatevoidspawnRaindrop(){Spriteraindrop=newSprite(dropImage);raindrop.setX(MathUtils.random(0,width-raindrop.getRegionWidth()));raindrop.setY(height);raindrops.add(raindrop);lastDropTime=TimeUtils.nanoTime();

    }

    ThisSpriteiscreatedwithnew.GCwillstillhappenasnormalandaslongastheobjectscreatedaresmall,thereshouldn’t beabigimpact.

    @Overridepublicvoidrender() {//clearthescreenwithadarkbluecolor.TheargumentstoglClearColor arethered,greenblueandalphacomponent//intherange[0,1]ofthecolor tobeusedtoclearthescreen.Gdx.gl.glClearColor(0, 0,0.2f,1);Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    //tellthecameratoupdateitsmatrices.camera.update();

    //telltheSpriteBatch torenderinthecoordinatesystemspecifiedbythecamera.batch.setProjectionMatrix(camera.combined);

    //beginanewbatchanddrawthebucketandalldropsbatch.begin();bucket.draw(batch);for(Spriteraindrop: raindrops){

    raindrop.draw(batch);}batch.end();

    ...

    Notreallynecessaryheresincethecameraisnotchanging

    rendermethod:part1/3

    ...

    //processuserinputif(Gdx.input.isTouched()) {Vector3touchPos =newVector3();touchPos.set(Gdx.input.getX(), Gdx.input.getY(),0);camera.unproject(touchPos);bucket.setX(touchPos.x - bucket.getWidth()/2);

    }if(Gdx.input.isKeyPressed(Keys.LEFT)) bucket.translateX(-400*Gdx.graphics.getDeltaTime());if(Gdx.input.isKeyPressed(Keys.RIGHT)) bucket.translateX(400*Gdx.graphics.getDeltaTime());

    //makesurethebucket stayswithinthescreenboundsif(bucket.getX()<0)bucket.setX(0);if(bucket.getX()>width- bucket.getWidth())bucket.setX(width- bucket.getWidth());

    //checkifweneedtocreateanewraindropif(TimeUtils.nanoTime() - lastDropTime >1000000000) spawnRaindrop();

    ...

    rendermethod:part2/3...

    //movetheraindrops, removeanythatarebeneath thebottomedgeof//thescreenorthathitthebucket.Iteratoriter =raindrops.iterator();while(iter.hasNext()){Spriteraindrop=iter.next();raindrop.translateY(-200*Gdx.graphics.getDeltaTime());if(raindrop.getY()+raindrop.getHeight()<0)iter.remove();if(raindrop.getBoundingRectangle().overlaps(bucket.getBoundingRectangle())){iter.remove();

    }}

    }

    rendermethod:part3/3

  • @Overridepublicvoiddispose(){//disposeofallthenativeresourcesdropImage.dispose();bucketImage.dispose();batch.dispose();

    }}

    Whatneedstobedisposedof?AnyclassesthatimplementDisposable.

  • Example:“ZenGarden”

    • ”ASimpleGame”• Rainfallsrandomlyfromthesky• Usercontrolsabuckettocatchraindrops

    • Hereweinvertthissetup• Usercontrolsacloudinthesky,fromwhichraindropsfall• Ifrainfallsonatree,thetreegrows

    • Downloadthecodeforthisexample(seenotespage)• Themainfiles:• ZenGardenGame (extendsApplicationAdapter)• Tree(interface)• SimpleTree (implementsTree)• RecursiveTree (implementsTree)

    • First,considerSimpleTree’s drawmethod…

    publicvoiddraw(SpriteBatch batch){//Anaffine transformisusedtorepresenttranslation, rotation,andscalingoperations.Affine2 transform=newAffine2();

    //Initialtranslationandrotation,bringingustothebaseofthetree,pointedupwards.transform.translate(baseX,baseY);transform.rotate(90.0f);

    //Storethecurrenttransformstateforusebelow.Affine2savedTransform =newAffine2(transform);

    drawBranch(batch,transform);

    ….privatevoiddrawBranch(SpriteBatch batch,Affine2 transform){//Drawthecurrentbranch.Wedrawitastwohalvesbecausetransformationssuchas//rotationaremadewithrespecttothelowerleftcorneroftheimage.batch.draw(stickLeft,stickLeftWidth,stickLeftHeight,transform);transform.scale(1f,-1f);batch.draw(stickRight,stickRightWidth,stickRightHeight,transform);transform.scale(1f,-1f);

    }

    drawmethod:part1/2

  • //Translatetothefirstbranchingpointtransform.translate(stickLeftWidth *0.86f,0);

    //Drawthefirstbranchtransform.rotate(30.0f);transform.scale(FIRST_BRANCH_SCALE,FIRST_BRANCH_SCALE);drawBranch(batch,transform);

    //Repositiontosecondbranchingpointbyrestoringthesavedtransform.transform=savedTransform;transform.translate(stickLeftWidth *0.55f,0);

    //Drawthesecondbranchtransform.rotate(-30.0f);transform.scale(SECOND_BRANCH_SCALE,SECOND_BRANCH_SCALE);drawBranch(batch,transform);

    }

    drawmethod:part2/2

    • OnthepreviousslideweareusingtheSimpleTree classwhichdrawsthebasictrunkofthetreeandtwobranches.• RecursiveTree addsthefollowing:• Treegrowsinresponsetowaterdropsfallingonit• Treegrowsfractally byrecursivebranching• Whenatthemaximumgrowthlevel,berriesemerge!

    • Pleaseseetheattachedcodefordetails…


Recommended