COPYRIGHT NOTICE. COPYRIGHT 2007-2019 by Clinton Jeffery. For use only by the University of Idaho CS 328

Lecture Notes for CS 328 Introduction to Computer Game Development

Syllabus

Platform notes

We will do assignments this semester in Java. You will need to learn Java real fast if you do not know it. Fortunately Java is very mainstream and similar to C++ if you know that.

We will use a library called LibGDX. Most of the online tutorials for libGDX are youtube videos, so some of your "reading" assignments will be to watch videos. Don't blame me, this is your generation at work. I am trying to produce a decent text because I haven't found one. If you find a decent libGDX manual, online or in print, I want to know about it.

What's This Course About?

Big questions:
How can CS reduce the effort required to develop computer games?
What CS skills can we learn by studying game design and development?

What's This Course NOT About?

What is a Game

This course is about computer-based games, so what is a game? Can you define what a game is? Many definitions will miss the mark or fall well short. Dictionary.com lists 24 definitions.

The main definitions we will consider are

an amusement or pastime
OK, but are movies and TV games? No.
a competitive activity involving skill, chance, or endurance...
having rules, etc.
The first definition is missing the interactivity or mental or physical exercise implied in the second, but it captures the important aspect of fun. The second definition misses the "fun" and misses the potential of cooperative games versus traditional competitive games.

Throwing all this together one gets something like:

A competitive or cooperative activity involving skill, chance, or endurance, whose primary goals are amusement, improvement, or both.

"Reading" Assignment

Dr. J's Quick Take on the History of Computer Games

History is not the subject of this course, but here are a few brief landmarks. How many of the pioneering games do you know? This material is generally collected from appropriate googling off the web, supplemented occasionally from the author's memory.

1952 First computer game (?) might have been Alexander Douglas' computer version of Tic-Tac-Toe (Noughts and Crosses). Although this is a graphics display, it might as well be ASCII-art
1958-59 Higinbotham builds Tennis for Two
This is running on an analog computer. The screen is an oscilloscope.
Hardware implementation. One instance built for public demonstration.
This isn't Pong, but it seems valid to call it a predecessor.
Proof that Sports Games came before Shooters.

1961-62 Russel builds Spacewar
Software widely replicated as a "diagnostic tool".
Inspired videogame entrepreneurs.
Cloned into commercial existence in 1970's. A precursor for Asteroids.

Creative Commons/Kenneth Lu
1960's While spacewar was slowly propagating...
games such as checkers considered by A/I pioneers.
Punched card era also inspired trivial sim games (e.g. Hamurabi)
70's pencil RPG's
Textual games and ASCII art.
Usually turn-based. On-line == modems: rare and institutional.

The precursor to the FPS: Mazewar
late 70's Arcade games. Pong, space invaders, Pac Man...

Precursor 4k-64k personal computers often had lower fidelity graphics than the commercial arcades. Check out C64s.com

80's early multi-user games. (low-res) turn based strategy. Awesome console franchise empires such as Nintendo and Sega.

You just might be nostalgically attached to one or more iconic figures and franchises created in that era, such as Mario:

As much as I love that era, the closed and controlled nature of console development from that time has dark implications for the entire videogame industry.
90's FPS, RTS.
From id software came the game Doom, which catapulted PC gaming to the fore, and spurred intense development of low-cost mass market 3D graphics hardware.
2K+'s MMRPG, ...

Current Platforms

Customer expectations are approximately commensurate with the hardware capabilities of each platform.

Game Development via "Evolution"

Games are large and complex. This course can be considered a "specialized, media-rich software engineering class". You can try to build a game via the waterfall model:

Requirements Analysis
  • The gamer has an idea, not found in current games
  • Idea is explored, and a "vision" for a new game is realized.
Design
  • Game User Interface. File formats. Network communication protocols.
Implementation
  • Coding and Art. Ratio varies. Art is overwhelming coding in modern commercial games.
Testing
  • Hire gamers at $7.25/hour to test your game. Alpha and beta test.
Release
  • Release your game through a publisher and distributor, or via internet.
Maintenance
  • If you get this far, you are more successful than 98% of game efforts.

Actually, the waterfall model is "all wrong" for game development, which should probably follow a "natural evolution", meaning working prototypes start out with textual depictions of core game logic, proceed to simple graphics, and then evolve more powerful 3D and multi-user capabilities. Whether or not each individual game should evolve in this manner, there is another possible application of the metaphor.

Corollary Evolutionary Hypothesis: just as embryos, fetuses, and infants are claimed to go through the earlier stages of evolution of our species, our individual capability to write computer games might best be "grown" one game at a time by implementing each and every game and game genre that was previously done by our ancestors. When we can clone Wow, then we can talk about implementing Wow's successor.

Popular Game Genres and Mechanics

Although many games span multiple genres
parlor games
computer versions of manual games can be very popular.
text adventures
textual games that require players to solve puzzles and mysteries
arcade
2D games of exploration or survival
first person shooters
3D real-time games of combat/survival
How do you know when you win? Popular game mechanics include one or more of the following:
survival
run, or shoot, until you die. Examples: Space Invaders, Doom
escape
win by getting out
genocide
win by eliminating the opponent. Example: checkers
assassination
win by killing the enemy king. Example: chess, stratego.
collection
win by completing your collection of rare and exotic items (or deeds)
construction
build cool stuff
tycoon
win by amassing the most money
celebrity
win by amassing the most "fame"
megalomania
win by taking over the world, a la Napoleon / Alexander / supervillain
tactics
win a battle, by accomplishing specific military objectives
strategy
win a war, by defeating the enemy across multiple battles. Usually involves out-resourcing, out-logisticsing, or out-sciencing them. Examples: Civilization, Warcraft
exploration
win by finding or discovering something, or everything
role-playing
you don't win, you just enhance your character, get "xp" and gain "levels"

... So Get to Work on Homework #1

Install:

Lecture 2

Mailbag

Is there a particular reason why you are recommending Oracle JDK (https://www.oracle.com/technetwork/java/javase/downloads/index.html) rather than OpenJDK (https://jdk.java.net/12/)?
LibGDX depends on some fancy graphics code under the hood. Historically, some versions of LibGDX did not work with some OpenJDKs. I tried a current-ish OpenJDK 11 last night, and it had a cryptic error trying to run the default libGDX project. This morning, I tried a BlueJ which came with its own OpenJDK 11 installation against the libgdx .jar's from our textbook website, and it ran. Maybe OpenJDK version 12 might work even better, or maybe not at all. You are welcome to read up on OpenJDK and try to use it with libGDX. If OpenJDK gives you trouble, you may need to run Oracle Java and that might affect what IDE's you can use.
Must I use my desktop with a GPU instead of my puny laptop?
In CS 328 you would probably get on just fine on your old laptop with integrated graphics, although Java is a Moose and compile speeds might be an issue. In CS 428, you might be happier on a GPU.

Short Intro to Java

Here are a few highlights, from Stemkoski Appendix B, assuming that you know C++ but not Java.

libGDX: Notes on Getting Started

How many have been able to run a libGDX demo, or pong, yet?

Gradle

So, what the heck is Gradle, anyhow?

BlueJ

Lecture 3

No Class Monday

Monday is Labor Day. We will next meet on Wednesday.

Reading

Homework #2

Time to dive into our first libGDX game.

Java extends Example

public class Person {
   int HP;
   public void attack(Person other) { ... }
}
public class Wizard extends Person {
   int Manna;
   public void castSpell(String spellname) { ... }
}
If you are designing your own software you use extends when a class is logically an extension or special case of another class.

When you are using someone else's class library, how do you use it?

  1. create instances of their classes, and call their methods.
  2. take their (abstract) classes and make your own subclasses of them, and use those.
  3. make subclasses of their abstract classes, and pass them into their other classes, where they call your stuff when they feel like it
#2 is when you start calling their class library a framework, instead of just a class library. #3 is a particular style of framework, an event-driven framework. LibGDX is a event-driven framework. You use it by declaring a subclass of a Game and use that object in a platform-specific Launcher.
public class HelloWorldImage extends Game {
   ... use defaults or override Game methods
}

public class HelloLauncher {
   public static void main(String [ ]args) {
      HelloWorldImage myGameObj = new HelloWorldImage();
      LwjglApplication launcher = new LwjglApplication(myGameObj);
   }
}

Interfaces in Java

For many libGDX classes, you can choose to either
  1. write a subclass of a library class and override its methods, which provide some default behavior.
  2. write a class that implements a corresponding interface --- provide the same methods with matching names, parameters, and return type.
public interface Speaker {
   public void speak();
}
Anyone who wants to be compatible with this interface writes
public class Person implements Speaker {
   public void speak() { // ... write an actual body of speak
   }
}
Language designer note: a smart language could figure out whether you implement the Speaker interface without you saying "implements Speaker", but Java makes you say it.

Having defined an interface, you use it my writing code that declares things as Speaker, for example a parameter. LibGDX does this in spades, internally, that is largely how it makes use of your code.

public class Player {
   public void talkTo(Speaker s) { s.speak(); }
}
We will see various textbook code in later examples that implements various libGDX interfaces. Before we go into the Starfish Collector code from Chapter 2, here is a bit more of the big picture. The book talks about actors, stages, and then presents a bunch of classes to organize their use.

Game Architecture

Parts of this material inspired by Andreas Oehlke's book, "Learning LibGDX Game Development".
Game = Game Assets + Game Logic

GDX is a Hexagonal Facade

Pong

Pong is almost the first arcade game, and introduces us to that genre. Basic principles of arcade games include: This course isn't really about computer graphics programming per se.

  • newPong.java

    Lecture 4

    BBlearn

    The course should be available now on Bblearn, with a place for you to turn in your homework #2. Let me know if it is not.

    The Six Core Modules of GDX

    All are accessed through a core class called Gdx. Gdx is a class not an object, but since you use it almost entirely in terms of static member variables, it can be thought of as a Singleton (design pattern) or as a package of global variables (ugh).

    They are introduced here in terms of responsibilities, with rudimentary example fragments to give the flavor of their API and typical uses.

    Gdx.app, the application module
    logging, shutdown, "persist" data, query platform and memory, and send messages to the render thread (if your program has other threads)
       Gdx.app.setLogLevel(Application.LOG_DEBUG);
       Gdx.app.exit();
       Preferences p = Gdx.app.getPreferences("settings.prefs");
       p.putInteger(key, val);
       p.flush();
       switch(Gdx.app.getType()) {
          ...
          }
       Gdx.app.postRunnable(new Runnable() {
          @Override
          public void run() { ... }
          });
    
    Gdx.graphics, the graphics module. Interestingly, there is a separate module Gdx.gl that provides almost exactly the API of OpenGL, the industry standard portable 2D and 3D graphics API. OpenGL is a whole big can of worms. Simple GDX programs might only directly reference it to clear the screen each frame; most graphics rendering is done through other GDX classes that turn around and call OpenGL.
    frame timing, display size, ...
       Gdx.graphics.getDeltaTime();
       Gdx.graphics.getFramesPerSecond();
       Gdx.graphics.getWidth();
       Gdx.graphics.getHeight();
       Gdx.gl.glClearColor();
       Gdx.gl.glClear();
    
    Gdx.input
    you have to implement an InputProcessor and set it. Warning: screen coordinates might have nothing to do with output display coordinates!
       Gdx.input.setInputProcessor();
       Gdx.input.getX();
       Gdx.input.getY();
       Gdx.input.isTouched();
       Gdx.input.isButtonPressed();
       Gdx.input.isKeyPressed();
    
    Gdx.files, the file system module
    The lowest common denominator is really low.
       Gdx.files.internal(); // app folders, e.g. assets
       Gdx.files.external(); // ~, or SD card
    
    Gdx.net, the network module
    HTTP, and lower-level networking
       Gdx.net.sendHttpRequest();
       Gdx.net.cancelHttpRequest();
       Gdx.net.newClientSocket();
       Gdx.net.newServerSocket();
    
    Gdx.audio, the audio module
    play sound f/x or music files. WAV, MP3 [, OGG].
       Gdx.audio.newSound();
       Gdx.audio.newMusic();
    

    The Starfish Collector code from Chapter 2

    Big questions interrupt us here:
    1. in an object oriented system, how do you tell which objects are in application source code, and which are in libraries?
    2. Where is the API and description of the Actor class, that Dr. Stemkoski's ActorBeta extends?
    Just keep following what you can see, and asking questions Summarizing all the libGDX functionality from Chapter 2 is almost a matter of: listing all the imports in all the .java files, and for each import, seeing what instances of that class are used and what methods of that class are called. This would give you "the subset of libGDX used by this game", a tiny projection of the overall gigantic libGDX library. Let's brute force that a bit.

    The following summary is all the imports from com.badlogic.gdx.... in chapter 2.

    scenes.scene2d.Actor
    These are "entities" that may appear on the screen and act/interact. API: act(), draw(), setSize(), setPosition(), setVisible(), getX(), getY(), ...
    graphics.Texture
    These are 2D images, typically loaded from files. API: getWidth(), getHeight()
    graphics.g2d.Batch
    Batch objects bundle together a number of graphic operations to be buffered and delivered together to the GPU. API: setColor(), draw()
    graphics.g2d.TextureRegion
    A TextureRegion allows a portion of a texture to be used as a texture, and allows multiple images to be substituted in as called for. API: setRegion()
    graphics.Color
    Holds r, g, b, and a values that may be used in output operations.
    math.Rectangle
    Basic math abstraction. API: setSize(), setPosition(), overlaps()
    Game
    Implements default values for (7?) standard methods required by an application (launcher) object. API: create(), initialize(), render(), update(), ...
    Gdx
    As discussed above, this is a facade for libGDX's major components. It just provides access to a lot of static functions. API: input.isKeyPressed(), graphics.getDeltaTime(), gl.glClearColor(), gl.glClear()
    graphics.GL20
    OpenGL 2.0 graphics things. API: GL20.GL_COLOR_BUFFER_BIT.
    scenes.scene2d.Stage
    Container that holds a bunch of Actors, and tells them all what to do at the appropriate times in the game's main loop. API: addActor(), act(), draw()
    backends.lwjgl.LwjglApplication
    The platform-specific code to run a Game on Lightweight Java Gaming Library
    ApplicationListener
    In general, Listener's are objects that ask to be informed of, and handle, when asynchronous events occur in other objects. Imported in StarfishCollectorBeta but not used.
    Input.Keys
    Keys.LEFT, Keys.RIGHT, Keys.UP, Keys.Down
    Lecture 5

    Highlights of Starfish Collector (Stemkoski, chapter 3)

    A Bit O Java

    Java has generics, which are the same thing as C++ templates.
    public class Pair<T>
    {
     private T first, second;
     ...
     Pair(T t1, T t2) { first = t1; second = t2; }
     // methods operate on the T's
    }
    
    Pair<String> z = new Pair<String>("Foo", "Manchu");
    

    Value Based Animation

    Image Based Animation

    What can we Learn from Pong

    Anything that appears in both Starfish Collector and Pong must be indispensable.

    GDX Naming

    Perhaps the reason GDX is often called libGDX is that if you google GDX you get some Gold Mining financials. I will use both GDX and LibGDX and consider the terms interchangeable.

    Beware openJDK

    Old Example: on my Fedora Linux at home, /usr/bin/java on my PATH was OpenJDK, and when I installed the Oracle Java, it was placed in /usr/java/jdk1.8.0_65/bin/java. I had to modify my ~/.profile to include /usr/java/jdk1.8.0_65/bin prior to /usr/bin. I set my JAVA_HOME to /usr/java/jdk1.8.0_65. Then gdx-setup ran for me.

    As a reminder, gdx-setup may take a couple few minutes to run, if it is downloading gradle and libgdx components. If you get to BUILD SUCCESSFUL then you finished OK. If you do NOT get BUILD SUCCESSFUL, you are NOT OK.

    Similarly, when you first run ./gradlew desktop:run it may take a couple minutes.

    A gdx-setup script

    If you run linux, you may want to place this somewhere on your path (as file gdx-setup), and marked user-executable (chmod u+x), this might save you some typing.
    #!/bin/sh
    java -jar ~/bin/gdx-setup.jar $*
    

    A 2nd look at the GDX "life cycle"

    Interface ApplicationListener has six methods, one for each system state:

    void create();
    typically: create/initialize all game state / objects
    void render();
    Erase/(re)draw application display, from scratch. Called once/frame. Many GDX applications also execute game logic from here, and even read user input.
    void resize(width, height);
    Called when a resize() occurs.
    void pause();
    Phone apps should be pausable at any time. How does this work for real-time multiplayer games? You also get a pause() on your way to a dispose().
    void resume();
    If you pause, you can be resumed. Its unclear whether you're guaranteed that a resume() will happen; the app could get terminated if memory reclamation requires it.
    void dispose();
    This is what you are called on your way to an exit. It should just free resources.
    The following dubious flow chart was given in a GDX book by Andreas Oehlke for the GDX life cycle. How does it compare with the simpler game loop from the last lecture?

    Starter Classes

    In a GDX application, the actual main() procedure is placed in a platform-specific starter class. It lives way off in a separate directory from where your application code lives. Minimize the code you change here, if you want to remain portable.
    package com.packtpub.libgdx.demo;
    import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
    import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
    public class Main {
       public static void main(String[] args) {
          LwjglApplicationConfiguration cfg = new
             LwjglApplicationConfiguration();
          cfg.title = "demo";
          cfg.width = 480;
          cfg.height = 320;
          new LwjglApplication(new MyDemo(), cfg);
       }
    }
    
    lecture 6

    Physics

    These notes are from [Oehlke]. Stemkoski Ch 3 provides a similar treatment.
    velocity
    speed, m/s
    terminalVelocity
    minima/maxima
    friction
    negative force, basically deceleration, applied equally to x and y, should not be a Vector2 but it is
    acceleration
    m/s/s just like in high school physics
    bounds
    a "bounding box", type Rectangle, for collision detection
    public void update(float deltaTime)
    {
       updateMotionX(deltaTime);
       updateMotionY(deltaTime);
       position.x += velocity.x * deltaTime;
       position.y += velocity.y * deltaTime;
    }
    
    "updateMotion*" should be called "updateVelocity*". It means to apply friction and acceleration. [Oehlke] uses the following algorithm. Stemkoski's is similar (is it identical?).
    1. if object is moving, apply friction, which always pulls toward 0
    2. apply acceleration
    3. cap abs(velocity) at +/- terminalVelocity

    Updating Motion

    Stemkoski does things a fair bit differently, actually.
    protected void updateMotionX (float deltaTime) {
       if (velocity.x != 0) {
          // Apply friction
          if (velocity.x > 0) {
             velocity.x =
                Math.max(velocity.x - friction.x * deltaTime, 0);
          } else {
             velocity.x =
                Math.min(velocity.x + friction.x * deltaTime, 0);
          }
       }
       // Apply acceleration
       velocity.x += acceleration.x * deltaTime;
       // Make sure the object's velocity does not exceed the
       // positive or negative terminal velocity
       velocity.x = MathUtils.clamp(velocity.x,
                      -terminalVelocity.x, terminalVelocity.x);
    }
    

    GDX MathUtils

    GDX Application Code Notes

    "implements ApplicationListener" vs. "extends ApplicationAdapter"
    extends ApplicationAdapter, used by gradle gdx-setup, inherits default versions of the six functions, so you override as needed.
    • Most smaller GDX apps benefit from subclassing ApplicationAdapter
    • If you are overriding all six, you get nothing from ApplicationAdapter so you might as well just implement.
    OrthographicCamera
    for 2D; for 3D one might switch to a perspective camera
    SpriteBatch
    In this context, a "batch" is a collection of graphics operations, buffered together for performance reasons. Similar concepts (e.g. Display Lists) are found in many graphics APIs.
    Texture
    A texture is a 2D image used within a larger scene. It is often a fill pattern. In 3D (triangular slices out of) textures are used to cover the faces of triangles. Also in 3D: many platforms/APIs require that the 2D texture images have width and height that are powers of 2. More about this later.
    TextureRegion
    Actually, in the industry it is pretty routine to lump together a whole ton of textures within a single, large 2D image, and then use different little slices out of a texture to define the fill patterns for different objects within a scene.
    Sprite
    A sprite is an object used for placement of a graphical object within a scene. Traditionally the term was used for 2D and if the placement was just an (x,y) a sprite was about the same as a texture. Because it is OpenGL-based, in GDX the concept of a sprite is a bit more sophisticated. It knows how to rotate and scale, and has a reference to a TextureRegion from which its visual contents are taken.

    Class Diagram for a GDX Game

    From Nair/Oehlke's libGDX book:

    Pixmaps and Textures

    Pixmap pixmap = new Pixmap(width, height, Format.RGBA8888);
    from com.badlogic.gdx.graphics.Pixmap
    pixmap.setColor(1, 0, 0, 0.5f);
    pixmap.fill();
    // Draw a yellow-colored X shape on square
    pixmap.setColor(1, 1, 0, 1);
    pixmap.drawLine(0, 0, width, height);
    pixmap.drawLine(width, 0, 0, height);
    // Draw a cyan-colored border around square
    pixmap.setColor(0, 1, 1, 1);
    pixmap.drawRectangle(0, 0, width, height);
    
    Texture texture = new Texture(pixmap);
    The way for you to think about it is: Pixmap lives in CPU memory, texture lives in GPU memory. Pixmap is easily writable; texture is almost write-once, read-only.

    Polling vs. Event-driven input

    Code like
       if (Gdx.input.isKeyPressed(Keys.A)) ...
    
    is an example of polling, "the continuous execution approach".

    LibGDX Topic for Today: InputProcessor

    InputProcessor vs. InputAdapter

    InputProcessor interface summary

    boolean keyDown(int keycode);
    start of a key "press"
    boolean keyUp(int keycode);
    end of a key "release"
    boolean keyTyped(char character);
    higher-level: this key was pressed. less common in video games because...
    boolean mouseMoved(int x, int y);
    pointer location, possibly without any key involved
    boolean scrolled(int amount);
    scroll wheel, amount may be positive or negative
    boolean touchDown(int x, int y, int pointer, int button);
    start of mouse click or finger "press"
    boolean touchDragged(int x, int y, int pointer);
    pointer movement while a pointer "pressed"
    boolean touchUp(int x, int y, int pointer, int button);
    end of a mouse click or finger "release"
    lecture 7

    Public Service Announcements

    1. Did you all see the game job hiring flyers posted in the JEB CS area?

    2. If anyone might be interested in internships, here's one.

    The Science & Engineering community at Hill AFB is accepting resumes for the Premier College Intern Program (PCIP) for qualifying JUNIORS interested in a paid summer internship (starting May 2020) that may lead to a full time developmental position after graduation.

    This program offers Juniors who are currently enrolled fulltime (12+ semester hours) in a qualifying 4-year program, a paid internship lasting 12 weeks in the summer prior to their senior year at the GS-04, Step 1 pay grade (approximately $14.54/hr).

    Requirements to qualify for the PCIP (not all inclusive) are as follows:

    Once students successfully complete the internship, they will return to school to complete their degree. Upon graduation, they may be non-competitively converted to a position within the 3-year PALACE Acquire (PAQ) Logistics Trainee Program. PAQ trainees will start at the GS-07 level and be eligible for promotion every 52 weeks through program completion. PAQ graduates are placed on permanent positions within the GS workforce.

    LOCATION OF INTERNSHIP: Hill Air Force Base (AFB), UT

    FOR INTERESTED STUDENTS TO APPLY: Please send Resume, Current Transcripts, and Proof of Full-Time Enrollment to: Cindy Pestotnik at cynthia.pestotnik@us.af.mil.

    DEADLINE: 30 Sep 19

    Recent Student install-libGDX Experiences

    Bit o Java for the Day

    ArrayList is dynamically-resizable generic list, with set operations.
    import java.util.ArrayList;
    public class bar {
     public static void main(String[]args) {
      ArrayList<String> names = new ArrayList<String>();
      names.add("Lee");
      names.add("Daniela");
      names.add("Chris");
      // names.size() would return 3
      // names.contains("Lee") would return true
      for (String name : names) {
       System.out.println(name);
      }
     }
    }
    
    The BaseActor class will extract/return for you (sub)lists of actors that are instances of a particular type/class on a given Stage:
      for (BaseActor rockActor : BaseActor.getList(mainStage, "Rock"))
    
    It's a bit "meta", but here is the getList method:
    public static ArrayList getList(Stage stage, String className)
    {
       ArrayList<BaseActor> list = new ArrayList<BaseActor>();
            
       Class theClass = null;
       try {  theClass = Class.forName(className);  }
       catch (Exception error) {  error.printStackTrace(); }
            
       for (Actor a : stage.getActors()) {
          if ( theClass.isInstance( a ) )
             list.add( (BaseActor)a );
       }
    
       return list;
    }
    

    Physics

    Compare this version of basic Physics (from Starfish Collector) with last lecture's.
    public void applyPhysics(float dt)
    {
       // apply acceleration
       velocityVec.add( accelerationVec.x * dt, accelerationVec.y * dt );
    
       float speed = getSpeed();
    
       // decrease speed (decelerate) when not accelerating
       if (accelerationVec.len() == 0)
          speed -= deceleration * dt;
    
       // keep speed within set bounds
       speed = MathUtils.clamp(speed, 0, maxSpeed);
    
       // update velocity
       setSpeed(speed);
    
       // apply velocity
       moveBy( velocityVec.x * dt, velocityVec.y * dt );
    
       // reset acceleration
       accelerationVec.set(0,0);
    }
    

    Collision Detections, first pass

    Collision Response and Prevention

    Suppose you detect a collision. What do you do? Depends on the game mechanics and the objects involved. You might: libGDX provides a relatively low-pain way to just prevent the overlap. You can ask overlapConvexPolygons to calculate a MinimumTranslationVector, if that's what your game calls for:
    public Vector2 preventOverlap(BaseActor other)
    {
       Polygon poly1 = this.getBoundaryPolygon();
       Polygon poly2 = other.getBoundaryPolygon();
    
       // initial test to improve performance
       if (!poly1.getBoundingRectangle().overlaps(poly2.getBoundingRectangle()))
          return null;
    
       MinimumTranslationVector mtv = new MinimumTranslationVector();
       boolean polygonOverlap =
          Intersector.overlapConvexPolygons(poly1, poly2, mtv);
    
       if ( !polygonOverlap )
          return null;
    
       this.moveBy( mtv.normal.x * mtv.depth, mtv.normal.y * mtv.depth );
       return mtv.normal;
    }
    

    World Boundaries

    Given a world coordinate system (0,0,width,height) Rectangle named worldBounds, here's code to force any given (rectangle-based) Actor stays within the world.
    public void boundToWorld()
    {
       if (getX() < 0) setX(0);
       if (getX() + getWidth() > worldBounds.width)    
          setX(worldBounds.width - getWidth());
       if (getY() < 0) setY(0);
       if (getY() + getHeight() > worldBounds.height)
          setY(worldBounds.height - getHeight());
    }
    A camera that follows (is centered on) an Actor may need to STOP following the Actor when it gets near an edge, or the camera's sliding window will be showing things beyond the world boundaries.

    Screens

    What I Learned about LibGDX on my Sabbatical (TTP)

    Will show show you bits of code when it sheds additional light on libGDX topics we are talking about. We will use it for examples when hitting specific topics.

    TTP's Technical Report

    Because a software engineering project deserves documentation. Check out the class diagram, etc.

    InputProcessor in the main TTP class

    lecture 8

    Games and Society

    See highlights from Games and Society

    Go through at least the first 15 or so slides.

    Thoughts on Games and Society

    Reading Assignment

    Read Stemkoski Chapter 4, it is pretty short, 15 pages or so.

    Using Stemkoski Code in a gdx-setup based project

    Arcade Games

    Asteroids (1979) is one of the earliest and simplest arcade games. SpaceWar in the 1960's appears as though it was clearly inspiration, but Asteroids was an incredible phenomenon when it came out. Stemkoski implements a very rough prototype for a similar game in Chapter 4 called Space Rocks.

    Chapter 4 discusses

    Let's see if we can find all these as we look through the code.

    lecture 9

    Status of HW#2

    Status of HW#3

    HW#3 is posted. 3 weeks for an arcade game. Give me more of a real-ish playable game this time.

    Reading Assignment

    If you haven't yet, read Chapters 4-6 of the text.

    LibGDX Notes

    Have you found libGDX's online reference yet?
    Useful to find the lists of methods for the many predefined classes, like Pixmap

    Game State, part 1: a Taxonomy of Visible Game Objects

    Decorations vs. Entities
    Most games have stateless eye candy (decorations) that contrasts with in-game entities that feature either mutable-state and/or interactive features that figure into the game mechanics.
    Objects vs. Items
    "Levels" in games such as side-scrollers divide entities up into two categories: objects that are permanent parts of the level, and items that go away when the user picks them up.
    You could represent Objects and Items by the same mechanism.
    But do you want to. Why or why not?

    Some Highlights of Space Rocks

    lecture 10

    Chapter 5 is long (43 pages) and covers a lot. It will take multiple lectures to hit the highlights, and I also want to be talking about game design.

    Java Feature of the Day: Lambdas

    public interface Function {
       public void run();
    }
    
    // code that wants to use
    public class ClientCode {
       private Function f;
       public void setFunction(Function func) { f = func; }
       public void useFunction() { f.run(); }
    }
    
    // "anonymous inner class"
       client.setFunction( new Function() {
                               public void run() { System.exit(0); }
    			   }
          );
    
    // lambda, method name etc. "inferred"
       client.setFunction( () -> { System.exit(0); } );
    

    Text and User Interfaces

    Stemkoski Chapter 5 presents materials on displaying text and implementing user interfaces in two contexts:

    LibGDX Features relevant to Text

    Basic Gdx Text Display

    Adapted/updated non-trivially from gamefromscratch.com:

    Heiro

    FreetypeFontGenerator

    FreeTypeFontGenerator fg = new
       FreeTypeFontGenerator(Gdx.files.internal("assets/myFont.ttf"));
    FreeTypeFontParameter fp = new FreeTypeFontParameter();
    fp.size = 48;
    fp.color = Color.WHITE;
    fp.borderWidth = 2;
    fp.borderColor = Color.BLACK;
    fp.borderStraight = true;
    fp.minFilter = TextureFilter.Linear;
    fp.magFilter = TextureFilter.Linear;
    BitmapFont bf = fg.generateFont(fp);
    

    Bitmap Fonts in Labels

    For use in GUI's, e.g. with multiple buttons of similar appearance:
    public static LabelStyle labelStyle;
    ...
    labelStyle = new LabelStyle();
    // labelStyle.font = new BitmapFont(); // Arial 15
    labelStyle.font = new BitmapFont(Gdx.files.internal("myFont.fnt"));
    ...
    private Label starfishLabel;
    starfishLabel = new Label("# remaining: ", labelStyle);
    starfishLabel.setColor(Color.CYAN);
    starfishLabel.setPosition(20, 520);
    uiStage.addActor(starfishLabel);
    ...
    starfishLabel.setText("# remaining: " + num);
    

    Buttons

    ButtonStyle bs = new ButtonStyle();
    // ...  init buttonstyle parameters
    Button restartButton = new Button (bs);
    restartButton.setColor(Color.RED);
    restartButton.setPosition(720,520);
    uiStage.addActor(restartButton);
    ...
    restartButton.addListener(
      (Event e) -> {
          if (!(e instanceof InputEvent) ||
              !((InputEvent)e).getType().equals(Type.touchDown) )
             return false;
          StarfishGame.setActiveScreen( new LevelScreen() );
          return false;
       }
    );
    

    lecture 11

    Game Design

    We did slides 1-28

    lecture 12

    Game Design

    A couple more points from the slide deck. We may talk about design more later.

    Stemkoski Notes (Ch5)

    Ninepatches
    Because GUI widgets need to look "decent" on a wide range of display sizes
    Accessibility Principle #1: Redundancy
    Important elements of the user interface might have 2+ ways of invoking them, for mouse pointer vs. for touch vs. for keyboard for example.

    LibGDX Tables

    Table t = new Table();
    t.add(a);
    t.add(b);
    t.row();
    t.add(c);
    t.add(d);
    
    add() returns the Cell instance that was created/added to the table so you may well see some or all calls to add stored in member variables or collection classes in order to provide more direct access to specific cells.
    Table t = new Table();
    foo = t.add(a);
    bar = t.add(b);
    t.row();
    baz = t.add(c);
    zap = t.add(d);
    
    Example: Starfish Collector title screen wants a big label spanning two buttons underneath.
    Table uiTable = new Table();
    uiTable.setFillParent(true);
    uiStage.addActor(uiTable);
    uiTable.add(title).colspan(2);
    uiTable.row();
    uiTable.add(startButton);
    uiTable.add(quitButton);
    
    As another example, from the main screen HUD:
    uiTable.pad(10);
    uiTable.add(starfishLabel).top();
    uiTable.add().expandX().expandY();
    uiTable.add(restartButton).top();
    
    This places the points on the left and the restart on the right, both at the top of the HUD.

    A Good LibGDX Game Example from the Web

    With particularly good running commentary. Consider this a reading assignment.

    These are things you should learn as a by-product of looking at the Rain Catcher game.

    1. Setup practice. You should actually create a few projects with gdx-setup to get a feel for its parameters and options, and find out (for example) the simplest package organization that it will take.
    2. Androidisms. I am not emphasizing Android in this class, but if we did, we'd probably want to learn more about AndroidManifest.xml.
    3. Launcher. This launcher creates a window that's 800x480. But is that virtual 800x480, or physical 800x480? Compare the desktop, HTML, and android launchers. What is common? What is different?
    4. Cameras let you set a virtual resolution, independent of physical. Cameras have to be applied to SpriteBatch objects. camera.unproject() is interesting, what does it do?
    5. Assets. Many uses of Gdx.files.internal("..."). Preloading at create() time vs. loading on demand. Caching loaded assets vs. reloading. Under what circumstances do assets need to be freed?
    6. Rectangles. Note that they are pure math. Graphical rendering is completely separate.
    7. What is the difference between an array in Java, an Array in libGDX, and an ArrayList in Java?
    8. In general, games that play in real-time should avoid garbage collections, by statically allocating all resources. What does this entail?
    9. How does this program implement raindrops falling at 200 pixels/second?
    10. How does this program organize its Model View Controller?
    11. What is an Iterator and how do they work?

    lecture 13

    Q&A

    From a student:
    GUIs use an event-processing loop, but games like Pong and Breakout seem to want to own the event loop, what do I do?
    Obvious options include: 1) implement your own GUI so you don't give up control of the main loop, or 2) chop your action into tiny slices and make them fit in whatever correct spots the GUI allows such thing. GUIs often offer either an "idle function" (called when no user input is available) or a "clock" or "alarm" event (called periodically at programmable time steps). Perform one iteration of what used to be your main loop either each time you get control, or more likely, once every so many calls, after you can tell enough real time has elapsed. LibGDX tends to tell you (or allow you task) how many milliseconds since the last render; some things like 2D animation can be broken smoothly into such chunks, while other things need to only happen when larger time units have passed.

    Another Look at Resources/Assets

    "Resources" was the Windows dev. term; "assets" seems to be the GDX term. Means: images, sounds and the like that are bundled with and used in your program.
    GUI programs, beginning with Xerox Alto, use Large amounts of static data along with the code.
    The (binary image/sound) data is edited differently than code
    (ancient) DOS Model: ship a directory, load from files
    pros and cons; "open", assets easy to steal, insecure etc.
    (classic) Mac Model: deal with this in the OS
    filesystem has resource fork and data fork
    (classic) Windows Model: deal with this in the compiler/linker
    "Resource Compiler" turns .bmp into .obj for example
    Cloud Model: (re)download as needed from URLs
    popular in web apps and other thin clients. Note that this imposes severe constraints on asset richness and/or internet speed/quality.
    Tablet/Phone Model: ship a directory, load from files
    package it as an "App" instead of a .zip file, includes installer etc.

    Collections of Images and Texture Atlases

    GDX Texture Packer

    Loading and Tracking Assets

    We have already seen:
     Texture texture =
        new Texture(Gdx.files.internal("texture.png"));
     ...
     batch.draw(texture, x, y);
    

    Level Data

    In real games, level design is a major issue; a level editor often has to be built.

    CanyonBunny Source

    I'm sharing a bunch of sidescroller sample code from a program called CanyonBunny that was written by Andreas Oehlke and described in a book on libGDX. I used the book in a previous instance of CS 328 but students and I felt that it was not really great as a textbook for this course. Nevertheless, feel free to check it out:

    Discussion of Launcher Icons

    What the program looks like when it is not running. You would see it in the File Explorer, for any code or data file which, if clicked, would run your program. Classically icons in Windows were small, e.g. 16x16 or 32x32. Modern systems may use 64x64 or larger, or allow multiple icon sizes for different purposes, e.g. in a menu (small) versus in a file explorer window (large).

    lecture 14

    Midterm Date Selection

    Signs and Dialog Boxes [Stemkoski Ch5]

    public class DialogBox extends BaseActor {
       private Label dialogLabel; // ...
    }
    public class Sign extends BaseActor {
       private String text;
    }
    ... within the update method:
    
    for(BaseActor signActor : BaseActor.getList(mainStage, "Sign")) {
       Sign sign = (Sign)signActor;
       ...
       boolean nearby = turtle.isWithinDistance(4, sign);
       if (nearby && !sign.isViewing) {
          dialogBox.setText( sign.getText() );
          dialogBox.setVisible( true );
          sign.setViewing( true );
       } else if (sign.isViewing && !nearby) {
          dialogBox.setText(" "); // probably unnecessary
          dialogBox.setVisible(false);
          sign.setViewing( false );
       }
    }
    

    Cutscenes

    Each SceneSegment provides start(), finish(), and isFinished() methods that facilitate a Scene's playback of a sequence of SceneSegments.

    Class Scene's loadNextSegment() looks like:

    public void loadNextSegment()
    {
       if ( isLastSegment() ) return;
       segmentList.get(index).finish();
       index++;
       segmentList.get(index).start();
    }
    
    All of this delightful stuff is perhaps best viewed in the project it was written for:

    The Missing Homework Game

    I really wanted the punchline of this one to be something based on "my dog ate my homework", but its nothing so sophisticated as that.

    Java Constructor Question, from another libGDX game

    class Rock extends AbstractGameObject. Does its constructor inherit or otherwise do the work of initializing fields performed in the constructor for AbstractGameObject?

    public abstract class AbstractGameObject {
       public Vector2 position, dimension, origin, scale;
       ...
       public AbstractGameObject() {
          position = new Vector2();
          dimension = new Vector2(1, 1);
          origin = new Vector2();
          scale = new Vector2(1, 1);
          ...
       }
    }
    ...
    public class Rock extends AbstractGameObject {
    ...
    public Rock() {
       init();
       }
    }
    
    A: Because the AbstractGameObject has a default constructor, that is, one with no parameters, yes, it is called prior to Rock's own constructor, on each Rock instance that gets created.

    Tiling Images

    For now, you do not need to be a tiling expert, but you should know what it is, and know that you could learn to go do it (in PhotoShop or GIMP) if you needed to. There are high powered algorithms to tile an image automatically, but they give mixed results. For some applications they work well.

    The best general introduction on tiling that I know is Paul Bourke's Tiling Textures on the Plane. It is old but good.

    SpriteBatch draw()

    This is one of twelve (12!) draw() methods within class SpriteBatch. Lots of complexity.
    public void draw(
    	Texture texture,
    	float x, float y,
    	float originX, float originY,
    	float width, float height,
    	float scalex, float scaleY,
    	float rotation,
    	int srcX, int srcY,
    	int srcWidth, srcHeight,
    	boolean flipX, boolean flipY
    	);
    

    lecture 15

    LibGDX/Java Tidbit of the Day

    Swing vs. JavaFx

    JFx File Chooser

    Here's how to overly complicate a modal dialog:
       new JFXPanel();
       finished = false;
       Platform.runLater( () -> {
          FileChooser fileChooser = new FileChooser();
          File file;
          file = fileChooser.showOpenDialog(null);
          if (file != null) fileHandle = new FileHandle(file);
          finished = true;
          }
          );
        while (!finished) {
        // wait for fileChooser
        }
        return fileHandle
    

    Audio

    So, what will it take for us to get some more audio into our final projects? What kinds of audio would be useful in your project? Where can you get it?








    I would think it might include:

    Audio in LibGDX

    GDX plays
    .wav
    .wav is a Microsoft uncompressed PCM file format. Fine for short sound effects, too big/fat for longer music
    .mp3
    heavily compressed, proprietary format
    .ogg files
    heavily compressed, open source format
    We earlier saw the two interfaces
    Sound
    for effects < one second, load+decode hardwired together, intended to be sent straight to the device
    Music
    for longer sounds, a stream-oriented interface, to keep memory footprint from going crazy. Note streaming burns more CPU overall.

    Sound interface

       Sound sound = Gdx.audio.newSound(Gdx.files.internal("sound.wav"));
       ...
       id = sound.play(...); // control later via id
       ...
       sound.stop();         // or sound.stop(id);
       sound.dispose();
    
    Actually, there are three play() methods and three loop() methods that can be used: no parameters, a volume (0.0-1.0) parameter, or a three parameter call: volume, pitch, and pan. pitch raises (> 1.0) or lowers(< 1.0) frequency and playback speed. pan moves the sound left (< 0.0) or right (> 1.0). Volume, pitch, pan, and looping of a sound can also be set by calling set methods and passing an id.

    Music Interface

       Music music = Gdx.audio.newMusic(Gdx.files.internal("music.mp3"));
       ...
       music.play();
       music.pause();
       music.stop();
       ...
       music.dispose();
    
    There are setters on Music (setVolume, setPan, setLooping), as well as two queries: isPlaying() and getPosition(), where get position can say where (in ms) in the music the playback is at.

    Lower Level Audio Interfaces

    To give you an idea of how low-level they are, AudioDevice let's you write PCM-encoded audio samples directly to the device as an array of floats or shorts:

       AudioDevice audioDevice = Gdx.audio.newAudioDevice(samplerate, mono_p);
       ...
       audioDevice.writeSamples(samples, offset, numSamples);
       ...
       audioDevice.dispose();
    

    AudioRecorder reads 16-bit PCM samples (a.k.a. short ints) into an array:

       AudioRecorder audioRecorder =
          Gdx.audio.newAudioRecorder(samplerate, mono_p);
       ...
       audioRecorder.read(samples, offset, numSamples);
       ...
       audioRecorder.dispose();
    

    lecture 16

    Coeur D'Alene Students

    I am told your midterm must be taken at the NIC Testing Center. Please locate that facility, and see what requirements they will have for you to take that exam at 12:30 on October 18.

    Java Tidbits of the Day

    When to .size and when to .length













    More inner classes

    Stemkoski totally embraces "public inner classes" in his keystroke recorder. Also, note the totally intentional use of float vs. Float. What is the difference?
    public class SongData {
       private String songName;
       private float songDuration;
       ...
       public class KeyTimePair {
          private String key;
          private Float time;
          ...
       }
    }
    
    Having fun with glorified "csv" files:
    String rawData = f.readString();
    String[] dataArray = rawData.split("\n");
    song.setName(dataArray[0]);
    song.setDuration(Float.parseFloat(dataArray[1]));
    for (int i=2; i<dataArray.length; i++) {
       String[] keyTimeData = dataArray[i].split(",");
       String key = keyTimeData[0];
       Float time = Float.parseFloat(keyTimeData[1]);
       keyTimeList.add( new KeyTimePair(key, time));
    }
    

    super() and super.foo()

    In case I didn't discuss it, you should know in Java what these are and when are they used.











    super(arg1, ...)
    is how to invoke a superclass's non-default constructor, from within your constructor, in order to get inherited variables initialized
    super.foo(...)
    is how to invoke a superclass's version of method foo(), only needed if/when you override with your own (subclass) version of foo(), and usually invoked from within your version of foo(), in order to add or modify to what the superclass foo() is doing. This is called method combination and is common in OOP.

    Sound Generators

    sfxr
    RANDOMIZE until you are happy, then tune/tweak. Export to a .wav. cfxr is a Cocoa (Mac) version of sfxr featuring slight improvements.
    bfxr
    adds save/load/mix of multiple sounds. lock button in individual parameters. "Mutation" button makes it finally clear: these tools are using the human as a neural network evaluation function, LOL.

    Sound in Stemkoski Ch 6

    Note typographic error (p.144): newSound should read newMusic
    Sound effect = Gdx.audio.newSound(Gdx.files.internal("beep.wav"));
    Music song = Gdx.audio.newMusic(Gdx.files.internal("song.mp3"));
    

    Tips on Sounds from "CanyonBunny" (Oehlke)

    Triggers for audio at various points in the code then look like:
       AudioManager.instance.play(Assets.instance.sounds.jump);
    
    Note the lame use of .instance to refer to the (singleton) instance of the class. Can you think of alternatives?

    Audio Design

    lecture 17

    Reminder: Midterm October 18

    Audio Notes from GamaSutra

    Audio Programming

    An old deck on Audio; some background concepts and theory

    lecture 18

    HW#4

    Due date (10/12) was tweaked so that it is not due midterms week.

    Audio Programming

    An old deck on Audio; some background concepts and theory. Start from slide 14.

    Side Scroller (Stemkoski Ch7)

    Chapter 7 is a short chapter. You should read all of Stemkoski Ch. 7; I will hit the highlights in class.

    An Infinite (1D) Playground

    The relevant logic is an if-statement added to the act() method of such objects. This code assumes the infinite-scrolling object ("sky" or "ground") moves left at a constant rate. Some side-scrollers would instead be following the player's avatar around.
    public void act(float dt) {
       super.act(dt);
       applyPhysics(dt);
       if (getX() + getWidth() < 0) {
          moveBy( 2 * getWidth(), 0);
          }
    }
    

    Gravity

    public void act(float dt) {
       super.act(dt);
       setAcceleration(800);
       accelerateAtAngle(270); // down, in degrees
       applyPhysics(dt);
    
       for (BaseActor g : BaseActor.getList(this.getStage(), "Ground")) {
          if (this.overlaps(g)) {
             setSpeed(0);
    	 preventOverlap(g);
             }
         }
       if (getY() + getHeight() > getWorldBounds().height) {
          setSpeed(0);
          boundToWorld();
          }
    }
    

    Stars

    Enemy Planes

    Java Enums

    In a game like a side scroller, Java Enums might be a good way to interpret the level data presented as a big image, interpreting colors as contents at different locations within a level. Code that reads/parses level information and instantiates a game's data structures from it might be called a level loader.

    Before looking at the level loader:

    public enum BLOCK_TYPE {
       EMPTY(0, 0, 0), // black
       ROCK(0, 255, 0), // green
       PLAYER_SPAWNPOINT(255, 255, 255), // white
       ITEM_FEATHER(255, 0, 255), // purple
       ITEM_GOLD_COIN(255, 255, 0); // yellow
       private int color;
       private BLOCK_TYPE (int r, int g, int b) {
          color = r << 24 | g << 16 | b << 8 | 0xff;
       }
       public boolean sameColor (int color) {
          return this.color == color;
       }
       public int getColor () {
          return color;
       }
    }
    

    lecture 19

    A Sample Sidescroller's class Level

    Ideas from Oehlke's libGDX book, which describes a sidescroller game called CanyonBunny.
    public class Level {
       ... enum...
       // objects
       public Array<Rock> rocks;
       // decoration
       public Clouds clouds;
       public Mountains mountains;
       public WaterOverlay waterOverlay;
       public Level (String filename) {
          init(filename);
          }
       private void init (String filename) { ... }
       public void render (SpriteBatch batch) { ... }
    }
    

    method init()

    private void init (String filename) {
       // objects
       rocks = new Array<Rock>();
       // load image file that represents the level data
       Pixmap pixmap = new Pixmap(Gdx.files.internal(filename));
    
       // scan pixels from top-left to bottom-right
       int lastPixel = -1;
       for (int pixelY = 0; pixelY < pixmap.getHeight(); pixelY++) {
          for (int pixelX = 0; pixelX < pixmap.getWidth(); pixelX++) {
             ...
    	 float baseHeight = pixmap.getHeight() - pixelY;
             int currentPixel = pixmap.getPixel(pixelX, pixelY);
             ...
          }
       }
    }
    
          if (BLOCK_TYPE.EMPTY.sameColor(currentPixel)) {
             // do nothing
             }
    
          else if (BLOCK_TYPE.ROCK.sameColor(currentPixel)) {
             if (lastPixel != currentPixel) {
                obj = new Rock();
                float heightIncreaseFactor = 0.25f;
                offsetHeight = -2.5f;
                obj.position.set(pixelX, baseHeight * obj.dimension.y
                                   * heightIncreaseFactor + offsetHeight);
                rocks.add((Rock)obj);
                }
             else {
                rocks.get(rocks.size - 1).increaseLength(1);
                }
             }
          // player spawn point
          else if (BLOCK_TYPE.PLAYER_SPAWNPOINT.sameColor(currentPixel)) {
             ...
             }
          // feather
          else if (BLOCK_TYPE.ITEM_FEATHER.sameColor(currentPixel)) {
             ...
             }
          // gold coin
          else if (BLOCK_TYPE.ITEM_GOLD_COIN.sameColor(currentPixel)) {
             ...
             }
          // unknown object/pixel color
          else {
             int r = 0xff & (currentPixel >>> 24); //red color channel
             int g = 0xff & (currentPixel >>> 16); //green color channel
             int b = 0xff & (currentPixel >>> 8); //blue color channel
             int a = 0xff & currentPixel; //alpha channel
             Gdx.app.error(TAG, "Unknown object at x<" + ... + ">");
             }
          lastPixel = currentPixel;
          }
       }
       ... create and initialize decorations, which aren't part of the level map
    

    User Interface

    So what is the user interface for a game?

    In WorldRenderer:
    private OrthographicCamera cameraGUI;
    private void init () {
       batch = new SpriteBatch();
       camera = new OrthographicCamera(Constants.VIEWPORT_WIDTH,
                                       Constants.VIEWPORT_HEIGHT);
       camera.position.set(0, 0, 0);
       camera.update();
       cameraGUI = new OrthographicCamera(Constants.VIEWPORT_GUI_WIDTH,
                                          Constants.VIEWPORT_GUI_HEIGHT);
       cameraGUI.position.set(0, 0, 0);
       cameraGUI.setToOrtho(true); // flip y-axis
       cameraGUI.update();
    }
    
    public void resize (int width, int height) {
       camera.viewportWidth = (Constants.VIEWPORT_HEIGHT
                                 / (float)height) * (float)width;
       camera.update();
       cameraGUI.viewportHeight = Constants.VIEWPORT_GUI_HEIGHT;
       cameraGUI.viewportWidth = (Constants.VIEWPORT_GUI_HEIGHT
                                 / (float)height) * (float)width;
       cameraGUI.position.set(cameraGUI.viewportWidth / 2,
                              cameraGUI.viewportHeight / 2, 0);
       cameraGUI.update();
    }
    
    The actual display render() is then two calls to two render functions using two cameras:
    private void renderGui (SpriteBatch batch) {
       batch.setProjectionMatrix(cameraGUI.combined);
       batch.begin();
       // draw collected gold coins icon + text
       // (anchored to top left edge)
       renderGuiScore(batch);
    
       // draw extra lives icon + text (anchored to top right edge)
       renderGuiExtraLive(batch);
       // draw FPS text (anchored to bottom right edge)
       renderGuiFpsCounter(batch);
       batch.end();
    }
    
    public void render () {
       renderWorld(batch);
       renderGui(batch);
    }
    

    Side Scroller: potential next steps

    Actors

    Bunny Head

    It has to be able to move, jump, fall, and fly. It doesn't have to violate OO principles of encapsulation with all these public variables, but it does it anyway.
    public class BunnyHead extends AbstractGameObject {
    private final float JUMP_TIME_MAX = 0.3f;
    private final float JUMP_TIME_MIN = 0.1f;
    private final float JUMP_TIME_OFFSET_FLYING = JUMP_TIME_MAX - 0.018f;
    
    public enum VIEW_DIRECTION {LEFT, RIGHT};
    public enum JUMP_STATE {
       GROUNDED, FALLING, JUMP_RISING, JUMP_FALLING
       };
    
    public VIEW_DIRECTION viewDirection;
    public float timeJumping;
    public JUMP_STATE jumpState;
    public boolean hasFeatherPowerup;
    public float timeLeftFeatherPowerup;
    
    public BunnyHead() { init(); }
    
    public void init() { ... }
    
    public void setJumping(boolean jumpKeyPressed) { ... }
    public void setFeatherPowerup(boolean pickedUp) { ... }
    public boolean hasFeatherPowerup() { ... }
    }
    
    The init() code is fairly obvious constructors and physics initalization. Not shown in class. Note that enum constants are referenced (ENUMTYPE.ENUMVALUE) and the .set() APIs for Points and Rectangles.

    The jumping code tracks the bunny behavior through a four-state finite automaton.

    public void setJumping (boolean jumpKeyPressed) {
       switch (jumpState) {
       case GROUNDED: // Character is standing on a platform
          if (jumpKeyPressed) {
             // Start counting jump time from the beginning
             timeJumping = 0;
             jumpState = JUMP_STATE.JUMP_RISING;
          }
          break;
       case JUMP_RISING: // Rising in the air
          if (!jumpKeyPressed)
             jumpState = JUMP_STATE.JUMP_FALLING;
          break;
       case FALLING:// Falling down
       case JUMP_FALLING: // Falling down after jump
          if (jumpKeyPressed && hasFeatherPowerup) {
             timeJumping = JUMP_TIME_OFFSET_FLYING;
             jumpState = JUMP_STATE.JUMP_RISING;
          }
          break;
       }
    }
    
    The real work in update() is mostly inherited, but the bunny overrides and adds:
    public void update (float deltaTime) {
       super.update(deltaTime);
       if (velocity.x != 0) {
          viewDirection = velocity.x < 0 ? VIEW_DIRECTION.LEFT :
                                           VIEW_DIRECTION.RIGHT;
       }
       if (timeLeftFeatherPowerup > 0) {
          timeLeftFeatherPowerup -= deltaTime;
          if (timeLeftFeatherPowerup < 0) {
             // disable power-up
             timeLeftFeatherPowerup = 0;
             setFeatherPowerup(false);
          }
       }
    }
    
    The bunny's motion updater modifies default velocity updates using the current jumping state.
    protected void updateMotionY (float deltaTime) {
       switch (jumpState) {
       case GROUNDED:
          jumpState = JUMP_STATE.FALLING;
          break;
       case JUMP_RISING:
          // Keep track of jump time
          timeJumping += deltaTime;
          // Jump time left?
          if (timeJumping <= JUMP_TIME_MAX) {
             // Still jumping
             velocity.y = terminalVelocity.y;
          }
          break;
       case FALLING:
          break;
       case JUMP_FALLING:
          // Add delta times to track jump time
          timeJumping += deltaTime;
          // Jump to minimal height if jump key was pressed too short
          if (timeJumping > 0 && timeJumping <= JUMP_TIME_MIN) {
             // Still jumping
             velocity.y = terminalVelocity.y;
          }
       }
       if (jumpState != JUMP_STATE.GROUNDED)
          super.updateMotionY(deltaTime);
    }
    

    Bunny render()

    The render() for the bunny overrides to change the color while powered up.
    public void render (SpriteBatch batch) {
       TextureRegion reg = null;
       // Set special color when game object has a feather power-up
       if (hasFeatherPowerup) {
          batch.setColor(1.0f, 0.8f, 0.0f, 1.0f);
          }
       // Draw image
       reg = regHead;
       batch.draw(reg.getTexture(), position.x, position.y, origin.x,
                  origin.y, dimension.x, dimension.y, scale.x, scale.y, rotation,
                  reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(),
                  reg.getRegionHeight(), viewDirection == VIEW_DIRECTION.LEFT,
                  false);
       // Reset color to white
       batch.setColor(1, 1, 1, 1);
    }
    

    Completing the Level Loader

    When we looked at class Level before, the loader:

    Now that we have discussed dynamic objects (Actors?), we can finish the Level loader, which was in class Level's init() method.

    ...
    goldcoins = new Array<GoldCoin>();
    feathers = new Array<Feather>();
    ...
    for (int pixelY = 0; pixelY < pixmap.getHeight(); pixelY++) {
       for (int pixelX = 0; pixelX < pixmap.getWidth(); pixelX++) {
          ...
          ... if's for static entities such as Rocks, seen earlier
          ...
          // player spawn point
          else if (BLOCK_TYPE.PLAYER_SPAWNPOINT.sameColor(currentPixel)) {
             obj = new BunnyHead();
             offsetHeight = -3.0f;
             obj.position.set(pixelX, baseHeight * obj.dimension.y +
    		                  offsetHeight);
             bunnyHead = (BunnyHead)obj;
          }
          // feather
          else if(BLOCK_TYPE.ITEM_FEATHER.sameColor(currentPixel)) {
             obj = new Feather();
             offsetHeight = -1.5f;
             obj.position.set(pixelX, baseHeight * obj.dimension.y
    	                          + offsetHeight);
             feathers.add((Feather)obj);
          }
          // gold coin
          else if (BLOCK_TYPE.ITEM_GOLD_COIN.sameColor(currentPixel)) {
             obj = new GoldCoin();
             offsetHeight = -1.5f;
             obj.position.set(pixelX, baseHeight * obj.dimension.y
    	                          + offsetHeight);
             goldcoins.add((GoldCoin)obj);
          }
       }
    }
    
    The code for methods render() and update() just show class Level to be a true aggregate that calls render() and update() on all the Level's entities.

    lecture 20

    Bouncing and Collision Games (Stemkoski Ch 8)

    Short-ish (18 pages), about a game kinda too simple for us to spend too much time on, so we are just looking for interesting highlights again.

    On Game Design

    We did slides 1-19.

    lecture 21

    Drag and Drop (Stemkoski Ch 9)

    This is a 20 page chapter. With screenshots, that is still pretty short, and the games are perhaps not interesting to me personally. The user input techniques are applicable to other games, so they are still worth studying. The class Card developed here could be used in a wide range of games that use cards. Perhaps additional card-related classes (Deck, Hand, ...) would also be useful.

    Per earlier discussion of input, Drag and Drop is based on the InputProcessor interface, which has you implement the following event handlers. x and y are offsets relative to the object clicked, i.e. where within the object was it touched (or clicked).

    The main warning I had from previous libGDX experience is: there is not a 100% perfect sequence of touchDown()... followed by touchUp(), at least, not on every libGDX platform. We will see whether Stemkoski deals with this at all.

    Identity Crisis: this vs. self

    One of the downsides of lambdas, it turns out, is that they run in a temporary this object. It is faintly absurd that you can access the enclosing class instance's member variables but don't have a way to reference that instance without creating a fake "this" variable.

    DragAndDropActor and DropTargetActor: beware Java's Single Inheritance

    Although it is the most natural thing in the world to create lots of subclasses of BaseActor to describe different behaviors, I am not sure all of them should always be mutually exclusive. In Java the solution is always interfaces.

    Operations on Pairs of Objects: another Object Conundrum

    TextureRegion.split(texture, width, height)

    On Game Design, part 2

    Slides 20-43.

    lecture 22

    CDA Midterm Exam Revised Instructions

    CDA students: our CDA Associate Chair Bob Rinker went over and looked at the NIC Testing Center, and decided it would be better for you to take the exam on Friday at 12:30 at the Den if possible. See Carrie Morrison there, who will proctor your exam. If you cannot take the exam at the Den at 12:30, the NIC Testing Center is your backup plan and the midterm can be taken there at your appointed time; in that case, your midterm grade next Monday might or might not include your Midterm exam grade, since I might or might not receive the exam from them before the weekend.

    Midterm Exam Review

    This old CS 328 midterm may be interesting to you. Since we changed books, everything is different this year. Or is it? Our exam might be a mixture of shorter questions inspired by the reading assignments, plus something like this:

    Collision Handling After detecting the collision has happened, a game has to decide what to do about it.
    private void onCollisionBunnyHeadWithRock (Rock rock) {
       BunnyHead bunnyHead = level.bunnyHead;
       float heightDifference = Math.abs(bunnyHead.position.y
                                      - ( rock.position.y + rock.bounds.height));
    
       //
       // Left/right collisions.
       //
       // only trigger if rock sticks up high enough.  But note: abs() implies
       // it will also occur if rock is too far below. Is this correct?
       if (heightDifference > 0.25f) {
          // if x > half way through the rock, bunny hit from the right
          boolean hitRightEdge = bunnyHead.position.x > (
                                 rock.position.x + rock.bounds.width / 2.0f);
          if (hitRightEdge) {
             bunnyHead.position.x = rock.position.x + rock.bounds.width;
          } else {
             bunnyHead.position.x = rock.position.x - bunnyHead.bounds.width;
          }
          // Does a left/right collision really preclude any other type?
          return;
       }
    
       // A collision with rock was reported, but rock doesn't fit our definition
       // of an obstacle to our side.  It is above or below.
       switch (bunnyHead.jumpState) {
       case GROUNDED:
          break;
    
       case FALLING:      // colliding while falling == not falling any more
       case JUMP_FALLING:
          bunnyHead.position.y = rock.position.y +
    			      bunnyHead.bounds.height + bunnyHead.origin.y;
          bunnyHead.jumpState = JUMP_STATE.GROUNDED;
          break;
       case JUMP_RISING:  // colliding while rising == climb atop platform above?!
          bunnyHead.position.y = rock.position.y +
    			      bunnyHead.bounds.height + bunnyHead.origin.y;
          break;
       }
    }
    

    Input Processing

    CanyonBunny calls the following method each frame from the WorldController's update() method.
    private void handleInputGame (float deltaTime) {
       if (cameraHelper.hasTarget(level.bunnyHead)) {
          // Player Movement
          if (Gdx.input.isKeyPressed(Keys.LEFT)) {
             level.bunnyHead.velocity.x =
                -level.bunnyHead.terminalVelocity.x;
          } else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
             level.bunnyHead.velocity.x =
             level.bunnyHead.terminalVelocity.x;
          } else {
             // Execute auto-forward movement on non-desktop platform
             if (Gdx.app.getType() != ApplicationType.Desktop) {
                level.bunnyHead.velocity.x =
                   level.bunnyHead.terminalVelocity.x;
             }
          }
          // Bunny Jump
          if (Gdx.input.isTouched() || Gdx.input.isKeyPressed(Keys.SPACE)) {
             level.bunnyHead.setJumping(true);
          } else {
             level.bunnyHead.setJumping(false);
          }
       }
    }
    

    CanyonBunny: Losing Lives, and Ending the Game

    public boolean isGameOver () {
       return lives < 0;
    }
    public boolean isPlayerInWater () {
       return level.bunnyHead.position.y < -5;
    }
    
    If the game is over, we need to print a message and stop processing long enough for the player to digest their outcome. A variable timeLeftGameOverDelay tracks how much time we've spent on it. WorldController's update() skips input handling as long as you are in a "game over" state, which auto resets after a bit. Other games would require a user action to reset.
    public void update (float deltaTime) {
       if (isGameOver()) {
          timeLeftGameOverDelay -= deltaTime;
          if (timeLeftGameOverDelay < 0) init();
       } else {
          handleInputGame(deltaTime);
       }
       level.update(deltaTime);
       testCollisions();
       cameraHelper.update(deltaTime);
       if (!isGameOver() && isPlayerInWater()) {
          lives--;
          if (isGameOver())
             timeLeftGameOverDelay = Constants.TIME_DELAY_GAME_OVER;
          else
             initLevel();
       }
    }
    

    Multiple Screens

    In order to have a separate main menu screen, what are our options?
    1. Add a variable to the Game class, to indicate what screen we are on. Modify render() to switch on that variable.
    2. Subclass off of Game instead of off of ApplicationListener, and implement the Screen interface on two or more screens. Switch among them using Game's setScreen() method.
    Canyonbunny uses the Screen interface; there may be good reasons on some platforms.

    The AbstractGameScreen (re)allocates Assets whenever resumed, regardless of which Screen is active at any given time.

    public abstract class AbstractGameScreen implements Screen {
       protected Game game;
       public AbstractGameScreen (Game game) {
          this.game = game;
       }
       public abstract void render (float deltaTime);
       public abstract void resize (int width, int height);
       public abstract void show ();
       public abstract void hide ();
       public abstract void pause ();
    
       public void resume () {
          Assets.instance.init(new AssetManager());
       }
       public void dispose () {
          Assets.instance.dispose();
       }
    }
    
    The actual instantiated subclasses of AbstractGameScreen include the MenuScreen and GameScreen. MenuScreen eventually becomes artsy and has a menu on it. At first, though, it is just a pass-through to the game screen. In version 0 creates and switches to the game screen as soon as a touch (including click) occurs.
    public class MenuScreen extends AbstractGameScreen {
       private static final String TAG = MenuScreen.class.getName();
       public MenuScreen (Game game) {
          super(game);
       }
    
       @Override
       public void render (float deltaTime) {
          Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
          Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
          if(Gdx.input.isTouched())
             game.setScreen(new GameScreen(game));
       }
       @Override public void resize (int width, int height) { }
       @Override public void show () { }
       @Override public void hide () { }
       @Override public void pause () { }
    }
    
    The game screen is longer, and contains mostly stuff we have already seen, moved from the old Main class. Is there anything even remotely fishy here? (The new CanyonBunnyMain, presented further below after this, now extends GDX's Game class. Its create() creates a new MenuScreen and sets it as the current screen.)
    public class GameScreen extends AbstractGameScreen {
       private static final String TAG = GameScreen.class.getName();
       private WorldController worldController;
       private WorldRenderer worldRenderer;
       private boolean paused;
       public GameScreen (Game game) {
          super(game);
       }
       @Override
       public void render (float deltaTime) {
          // Do not update game world when paused.
          if (!paused) {
             // Update game world by the time that has passed
             // since last rendered frame.
             worldController.update(deltaTime);
          }
          // Sets the clear screen color to: Cornflower Blue
          Gdx.gl.glClearColor(0x64 / 255.0f, 0x95 / 255.0f,0xed /
                              255.0f, 0xff / 255.0f);
          // Clears the screen
          Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
          // Render game world to screen
          worldRenderer.render();
       }
       @Override
       public void resize (int width, int height) {
          worldRenderer.resize(width, height);
       }
       @Override
       public void show () {
          worldController = new WorldController(game);
          worldRenderer = new WorldRenderer(worldController);
          Gdx.input.setCatchBackKey(true);
       }
       @Override
       public void hide () {
          worldRenderer.dispose();
          Gdx.input.setCatchBackKey(false);
       }
       @Override
       public void pause () {
          paused = true;
       }
       @Override
       public void resume () {
          super.resume();
          // Only called on Android!
          paused = false;
       }
    }
    
    In order to switch back and forth between screens:
    private void backToMenu () {
       // switch to menu screen
       game.setScreen(new MenuScreen(game));
    }
    
    private Game game;
    public WorldController (Game game) {
       this.game = game;
       init();
    }
    

    New, supershrunk CanyonBunnyMain

    For what its worth, having emptied it out into screen classes, it now just loads assets and sets the screen.
    public class CanyonBunnyMain extends Game {
       @Override
       public void create () {
          // Set Libgdx log level

          Gdx.app.setLogLevel(Application.LOG_DEBUG);
          // Load assets
          Assets.instance.init(new AssetManager());
          // Start game at menu screen
          setScreen(new MenuScreen(this));
       }
    }
    

    Canyonbunny's Menu Screen

    How complicated is the following menu screen? How much code should it take?

    For better or for worse, what I would have done as a single .png with a input handler that checks mouse/touch within a couple squares on the right, CanyonBunny does with an enormous additional set of high-powered GDX concepts and classes that you can learn, if you want to use them in games.

    Scene Graphs

    A scene graph is a hierarchically organized structure of objects similar to files and folders on a hard disk.
  • In libGDX, the word Actor (which we were already using) is used to denote a node in a scene graph.
  • Each node can apply translation/rotation/scaling (applied via a transformation matrix) not just to itself, but to child nodes.
  • == nested, relative coordinate systems.
  • In traditional OpenGL this was all so totally standard that there was a special stack used to push and pop the transformation matrices.
  • I thought that was all out of vogue in modern OpenGL/direct X, but here it is again.

    Scene2D

    Having said all that, in order to do hit detection, you have to know objects' position and orientation, so of course it also has to take over rendering, particularly animation. -->

    lecture 23

    Where we are at in Class

    More Game Design

    Slides 44-60. We might want to talk about slides 61-66, but then again, maybe not necessary. I am fond of the short term memory limit, 7 +|- 2.

    lecture 24

    Mailbag

    Can we please have some more time to work on hw#4?
    Yeah OK, you can have through the weekend. The late clock will start ticking Sunday night. But, I will go ahead and post HW#5. And this game should be (for most of you) better than your last HW.
    Your talk about side scrollers sounds a lot like the topics of chapter 11, which describe platformers, do you want HW#4 to look like a side scroller or a platformer?
    Hmm, it is worse than that. Chapter 10 on tilemaps is one way to implement the level design for a platformer. I have not been a big fan of tiled and do not intend to assign you another homework that is a platformer. For HW#4 you should meet the specifications in the way that seems best to you, I will be flexible about accepting a game that scrolls over a larger area, whether it feels platformy or not.

    Discussion of Midterm Exam

    Game Writing and Interactive Storytelling

    We only discussed slides 1-10. 11-12 look useful but not sure they are worth going back in to that deck in class.

    lecture 25

    Semester Project

    We had a nice long discussion of the CS 328 semester project.

    Intro to Tilemaps and Tiled

    We got through the first three pages of chapter 10.

    Strategy games

    In the old (pre-PC) days, there was this awesome magazine called "Strategy & Tactics" from Simulations Publications, Inc.* Every couple months subscribers received a new issue, with a new strategy game in it (usually a "wargame"). A new map. New (cardboard counter) units. New rules. A new virtual world in which to conduct strategic battles.

    SPI was arguably the premier strategy gaming company, although its chief competitor Avalon Hill Games was possibly larger, and there were 1-2 other companies large enough to public magazines showcasing their new strategy games on a regular basis. Most game companies didn't do strategy or didn't come out with new titles very often.

    What is strategy? What is tactics?

    strategy
    a plan. how to string the battles together in order to win the war. Usually coarse-grained or long-term. Example: we will win the war by blockading the enemy's ports. They will (eventually) run out of resources and will be forced to either surrender, or leave their defensive position in order to obtain food and supplies. (A strategy that works well for islands like, say, England for example, or colonies dependent on port traffic).
    tactics
    techniques for using weapons/units in combination to win a battle. Generally fine-grained or short-term. Example: we will win the battle by sending drummers and torchbearers (with torches lit, hidden under clay jars) around their camp. Suddenly at like 2 in the morning, we will break the clay jars and make a ton of noise like we are attacking from all sides. This wil convince the enemy that we are far more numerous and confuse them into panicking/fleeing, after which we can pick them off easily.

    Real Time vs. Turn-based

    While Generals and battle commanders must function in real-time, they often rehearse their plans for hours (or days, or weeks), trying to test out all the unknowns, especially variations in enemy strength and behavior. While real battles involve massive-scale concurrent behavior on a continuous clock, simulations may use fixed time-slices and allow each unit to perform a selection of appropriate actions during their time slice.

    Real-time Strategy Games are usually a misnomer. The actions of players of real-time strategy games are usually tactics.

    Example Old-School Tabletop Turn-Based Strategy Games

    Example Turn-Based Strategy Computer Games

    Lots of tabletop games have been implemented on computers. Also, you might want to check out.

    Example Real-Time Strategy Games

    This subgenre first appeared on computers. Pros: time slices are tiny, in real life you can't micromanage thousands of units' behavior each time slice. Nice real-time graphics animations. Cons: relies very heavily on AI, even for human players.

    lecture 26

    Tiled Demo, part 2

    Chapter 10 is only 20 pages long; we covered the first three last time and will walk through the following Tiled topics today:

    Key Ideas from the TilemapActor Class

    Checkers / Damas (e.g. JGB Chapter 6)

    Checkers was one of the first games to be heavily studied in the field of artificial intelligence. Rules:

    In a previous edition of this class, one of the students wrote a very nice checkers game, complete with a reasonably smart A/I computer player. The algorithms used to optimize chess and checkers can be adapted to other strategy games to some extent. The Artificial Intelligence class is not a prerequisite for this one, so if you know it, use it, and if you don't know it, consider this a gentle introduction.

    Minimax Algorithm

    This material adapted from wikipedia, and from the wonderful pages of Dr. Bruce Rosen, with whom I once had the privilege of working. There is (or was) a nice interactive visualization of minimax available if you dare to turnon your applets, and this great YouTube video from Shaul Markovitch of the Technion might help (note however that he reverses the usual definition given below, and says circle is max and square is min).

    Let's start with a few definitions of special symbols:

    □ or △ : MAX node
    when it is your move you will maximize your position
    ○ or ▽ : MIN node
    your opponent will minimize your position
    β : Beta
    minimum upper bound of possible solutions
    α : Alpha
    maximum lower bound

    Given a "board position" P we wish to calculate our best possible move. This algorithm can be generalized to a broader class of strategy games, with "board position" replaced by the complete game state (in MVC terms, the model).

    (Source: Wikipedia)

    From the current position we select the next move as the child whose board position is best (maximizing our position).

    lecture 27

    Techniques for Platform Games (Chapter 11)

    Stemkoski Ch. 11 is about a platformer game named Jumping Jack, about a panda, named Jack. We looked at bit at a platformer from another libGDX book (Canyon Bunny), and platform games are pretty similar to the Starfish Collector game. What is in fact different about them?

    Highlights:

    Back to MiniMax Algorithm

    Youtube videos are great, but we need more examples.

    Tic-Tac-Toe and the Minimax Algorithm

    This is a wee bit of a tangent from checkers; file it under: "if tic tac toe needs this much of an evaluation function, how big would the evaluation of checkers (or chess) need to be?"

    Consider an explicit representation of the tic-tac-toe board: a list of lists of strings, with " " for unused, "x" for x, and "o" for o.

    L := [ [" ", " ", " "],
           [" ", " ", " "],
           [" ", " ", " "] ]
    
    Although this has appealing ascii-art properties, (ironically?) while playing with the evaluation functions, I found it useful to use numerically-based representation, with the different player marks represented by different primes, say 2 for "x" and 3 for "o".
    L := [ [1,1,1], [1,1,1], [1,1,1] ]
    
    Using this representation, you can tell if you have 2 or 3 in a row, and whether a row is blocked by the enemy, by multiplying the three numbers together.

    Based on this observation about tic-tac-toe, we might want to go and re-code checkers to use a similarly more numeric representation, but for now let's leave that question alone.

    procedure evaluate(L, player)
       if player=="x" then { player := 2; enemy := 3 }
       else { player := 3; enemy := 2 }
    
       # absolute results
       # 1000 if there exists a 3-in-a-row
       # -1000 if there exists an enemy 3-in-a-row
       if numNinaRow(L, player, 3)>0 then return 1000
       if numNinaRow(L, enemy, 3)>0 then return -1000
    
       # heuristic opinions
       sum := 0
       # + 100  for each (unblocked) 2-in-a-row
       # - 100  for each enemy (unblocked) 2-in-a-row
       sum +:= 100 * numNinaRow(L, player, 2)
       sum -:= 100 * numNinaRow(L, enemy, 2)
       # + 10   if we hold the center square
       # - 10   if we hold the center square
       if player = L[2,2] then sum +:= 10
       if enemy = L[2,2] then sum -:= 10
       # + 2    for each corner square
       # - 2    for each enemy corner square
       if player = L[1,1] then sum +:= 2
       if player = L[1,3] then sum +:= 2
       if player = L[3,1] then sum +:= 2
       if player = L[3,3] then sum +:= 2
       if enemy = L[1,1] then sum -:= 2
       if enemy = L[1,3] then sum -:= 2
       if enemy = L[3,1] then sum -:= 2
       if enemy = L[3,3] then sum -:= 2
       return sum
    end
    
    Counting how many N-in-a-row might look like:
    procedure numNinaRow(L, player, n)
       sum := 0
       n := player ^ n
       every i := 1 to 3 do {
          if L[1,i] * L[2,i] * L[3,i] = n then sum +:= 1
          if L[i,1] * L[i,2] * L[i,3] = n then sum +:= 1
          }
       if L[1,1] * L[2,2] * L[3,3] = n then sum +:= 1
       if L[1,3] * L[2,2] * L[3,1] = n then sum +:= 1
       return sum
    end   
    

    Checkers Implementation

    Reminder of purpose: a simple game in which to explore computer-controlled moves/behavior/decision-making in strategy games.

    What comes below are Unicon checkers implementation notes. Consider for each topic, how direct/easy would the LibGDX equivalents be?

    First, you need to represent the board. In Unicon this might be: a list of lists (in Java 2D array would be more native) of strings. Each string would start as " " (a string consisting of a space) and if it has a checkers piece, it would be assigned with a value like "red" or "white". Java might instead use an ENUM with a few values instead of a string in this situation..

    Allocation:
    UniconJava
       turn := "red"
       square := list(8)
       every !square := list(8, " ")
    
       turn = "red";
       String[][] square = new String[8][8];
       for(int i = 0; i<8; i++)
          for(int j = 0; j<8; j++)
             square[i][j] = " ";
    

    Initialization:
    every row := 1 to 3 do
       every col := 1 + (row % 2) to 8 by 2 do
          square[row,col] := "white"
    every row := 6 to 8 do
       every col := 1 + (row % 2) to 8 by 2 do
          square[row,col] := "red"
    
    for(int row=1; row <= 3; row++)
       for(int col = 1 + (row % 2); col <= 8; col += 2)
          square[row-1][col-1] = "white";
    for(int row=6; row <= 8; row++)
       for(int col = 1 + (row % 2); col <=  8; col += 2)
          square[row-1][col-1] = "red";
    
    To print the board / configuration to the console:

    write(" \\ 1 2 3 4 5 6 7 8 column")
    write("row -----------------")
    every i := 1 to 8 do {
       writes(" ", i, " ")
       every j := 1 to 8 do
          writes("|",square[i,j,1])
       write("|")
       write(" -----------------")
       }
    

    Gameloop:

    while find("red", !!square) & find("white", !!square) do {
       # draw the board
       # read the player's move and change the board
       if turn == "red" then turn := "white" else turn := "red"
       }
    
    Input:
       write(turn, "'s turn, move in row,col,...row,col format:")
       input := read()
       L := [ ]
       input ? while put(L, integer(tab(many(&digits)))) do =","
    
    ...and it is time to go into the full

    For what its worth (for comparison; not covering due to size):

    Minimax for Checkers

    Code here is "raw" and intended to resemble Wikipedia pseudocode. Algorithm in checkers.icn is more "cooked", i.e. packaged in an abstract class for better re-use.
    procedure minimax(node, depth, maximizingPlayer)
        if (depth = 0) | gameover(node) then {
            return evaluate(node)
    	}
        else if \maximizingPlayer then {
            every child := possiblemoves(node) do {
                if not (/α := (kidval := minimax(child, depth-1, &null))) then
    	        α <:= kidval
    	    }
            }
        else { # minimizing player
            every child := possiblemoves(node) do {
                if not (/α := (kidval := minimax(child, depth-1, 1))) then
    	        α >:= kidval
    	    }
            }
        return α
    end
    

    Good: allows perfect play [mathematically correct]

    Bad: requires infinite compute resources!

    Lecture 28

    HW#4 Status

    17/25 students have submitted solutions.

    Intro to Adventure Games (Stemkoski Ch. 12)

    Back to the Algorithm in checkers.icn

    This version is more "cooked", i.e. packaged in an abstract class for better re-use.

    Extending Minimax to RTS or MMO

    lecture 29

    Highlights from Stemkoski's "Treasure Quest"

    Alpha-beta pruning

    is an optimization to reduce the combinatorial explosion of minimax. If you think about it, we can discard parts of the tree when we know they cannot alter the result. Analogy: short-circuit boolean operators skip right-hand sides once it is known they cannot change the outcome.

    (Source: Wikipedia)

    More Resources for 2D Game Art

    You may need to make or buy some interesting game art, even for arcade games. What other online resources would you recommend?

    AI: Agents/Arch

    Got through this lecture: slides 1-4.

    lecture 30

    Reminder of Friday Presentations

    On Friday I am expecting you to Expect (and give) questions/suggestions from the audience. What would make each game proposal better?

    Reprise of Ch12 Demo

    Yeah, the sword must be a machete because it kills shrubs, not just bats.

    AI: Agents/Arch

    Got through this lecture: slides 5-20

    lecture 30

    This day was filled with student premises.

    lecture 31

    Bits of Java from Chapter 13

    public static final int FOO = 13;
    

    Alternative Sources of User Input

    Gamepads / Game Controllers

    Originally
    one of the main differences between 25cents/play Arcade Games and what you could play on videogame consoles at home was the user input controllers. Arcade Game controllers varied spectacularly and were heavyduty.
    Over time
    consoles have spent a ton of money on design improvements to their controllers. Differences in the Gamepads are a Major factor by which game consoles distinguish themselves in the crowded market. Compared with arcade games, they still suffer from "genericity" (often one controller for all games on a console, although less so over time).
    LibGDX Controller APIs: Typical polling every frame code:
    if (Controllers.getControllers().size > 0) {
       Controller g = Controllers.getControllers().get(0);
       float x = g.getAxis(XBoxGamePad.AXIS_X_LEFT);
       float y = -g.getAxis(XBoxGamePad.AXIS_Y_LEFT);
       Vector2 d = new Vector2(x,y);
       float length = d.len();
       if (length > 0.10 /* "dead-zone" epsilon */) {
          setSpeed(length * 100);
          setMotionAngle(direction.angle());
          }
       }
    else {
       /* ... old keyboard-polling code here */
       }
    
    Typical event-driven handler methods:
    public boolean buttonDown(Controller controller, int buttonCode)
    {
      if (buttonCode == XBoxGamepad.BUTTON_BACK) {
         ...
         }
      return false;
    }
    

    A Virtual Gamepad??

       Vector2 d = new Vector2(tpad.getKnobPercentX(),
                               tpad.getKnobPercentY());
       float length = d.len();
       if (length > 0 /* no "dead-zone" needed */) {
          setSpeed(length * 100);
          setMotionAngle(direction.angle());
          }
    
    

    GDX AI resources

    lecture 32

    AI: Agents/Arch

    Slides 21-.

    lecture 33

    Game Design Document

    Short fuse, because we don't have too much semester left. Due Sunday at midnight on bblearn. 3+ pages PDF to describe the game's rules, user interface, and content in words and pictures.

    AI: Techniques

    lecture 34

    Maze Games (Stemkoski Ch. 14)

    24 pages, pac man clone, algorithms for generating mazes, segues perfectly into our next A/I slide deck, which is on pathfinding.

    Maze Generation

       while there are rooms with neighbors that are not connected do
          select a room that possibly has unconnected neighbors
               (50%=most-recently-connected,50%=random selection)
          if selected room has an unconnected neighbor then
             select a random unconnected neighbor of thisRoom
             remove the walls between thisRoom and the neighbor
             mark the neighbor as connected
             add it to the end of the list
          else remove it from the list of rooms that may have unconnected neighbors
    

    The Ghost

       input: startRoom and targetRoom
       currentRoom = startRoom
       currentRoom.visited := true, put(list, currentRoom)
       while list is not empty do
          currentRoom := pop(list)
          for nextRoom := each unvisited neighbor do
              nextRoom.previous := currentRoom
              if nextRoom = targetRoom then return
              nextroom.visited = true
              put(list, nextroom)
    
    
    Q: for how many cells/rooms, and how many times per second, do you want the ghost resetting the visited flags on the entire map:
    public void resetRooms()
    {
      for (int gridY = 0; gridY < roomCountY; gridY++)
        for (int gridX = 0; gridX < roomCountX; gridX++) {
          roomGrid[gridX][gridY].setVisited(false);
          roomGrid[gridX][gridY].setPreviousRoom(null);
          }
    }
    
    Note: Stemkoski doesn't say this, but space is cheap. For small to medium sized game levels/maps, you can precalculate and store shortest paths from every room to every room. For larger spaces, you might clump collections of rooms together into equivalence classes... and/or implement a waypoint system.

    AI: PathFinding

    We did slides 1-13.

    lecture 35

    AI: PathFinding

    Start at slide 14.

    Peek at some extra reading/resources for game A/I

    lecture 36

    Reflections on Game A/I Chapters

    Demo of Ch. 14 Maze Game

    "Advanced 2D Graphics" (Stk Ch. 15)

    Some of these signs of polish for a finished game add substantively to the players' impression of how good your game actually is.

    The Particle Editor

    the Particle Editor

    ParticleEditor.jar is a standard-ish libGDX thing; see here. Note that Stemkoski's book github has a version of ParticleEditor.jar for you to use if you want; it seemed easier to me to get it there than the instructions on the libgdx website.


    (click for video)

    Intellectual Property, intro

    We only did the first couple slides from this slide deck.

    lecture 37

    Intro to Shader Programming

    GLSL data types

    GLSL operators and functions

    GLSL programs and variables

    Default Vertex Shader

    attribute vec4 a_position;
    attribute vec4 a_color;
    attribute vec2 a_texCoord0;
    uniform mat4 u_projTrans;
    varying vec4 v_color;
    varying vec4 v_texCoords;
    void main()
    {
       v_color = a_color;
       v_texcoords = a_texCoord0;
       gl_Position = u_projTrans * a_position;
    }
    
    What would have to be true for this program to make sense, executing thousands or millions of times in parallel, 60 frames per second?

    Default Fragment Shader

    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform sampler2D u_texture;
    void main()
    {
       gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
    }
    

    Shaders in/from LibGDX

    GrayScale Shader

    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform sampler2D u_texture;
    void main()
    {
       vec4 color = texture2D(u_texture, v_texCoords);
       float avg = (color.r + color.g + color.b) / 3.0;
       gl_FragColor = vec4(avg,avg,avg, color.a);
    }
    

    Custom Uniform Values

    This example illustrates adding a variable from your Java program into the shader in addition to all the parts transmitted by libGDX. It uses many vector-at-a-time dataparallel arithmetic operations to swing the turtle back and forth between color and grayscale along a sine curve.
    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform sampler2D u_texture;
    uniform float u_time;
    void main()
    {
       vec4 color = texture2D(u_texture, v_texCoords);
       float avg = (color.r + color.g + color.b) / 3.0;
       vec4 grayscale = vec4(avg,avg,avg, color.a);
       float value = (sin(6.28 * u_time) + 1.0) * 0.5;
       gl_FragColor = value * color + (1.0 - value) * grayscale;
    }
    
    To update the u_time variable each time the shader is used (after setting Java variable time as the sum of all elapsed time in the program.)
    batch.setShader(sp);
    sp.setUniformf("u_time", time);
    super.draw(batch, alpha);
    batch.setShader(null);
    

    Border Shader

    Bolds the border of an opaque object when it is surrounded by transparent background. Note that texture coordinates are "normalized" to (0.0-1.0) of the width and height of a texture. To compute a corresponding pixel location with an image, multiply the texture coordinates by image width and height.
    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform sampler2D u_texture;
    uniform vec2 u_imageSize;
    uniform vec4 u_borderColor;
    uniform float u_borderSize;
    
    void main()
    {
       vec4 color = texture2D(u_texture, v_texCoords);
       vec2 pixelToTextureCoords = 1 / u_imageSize;
       bool isInteriorPoint = true;
       bool isExteriorPoint = true;
    
       for (float dx = -u_bordersize; dx < u_bordersize; dx++) {
          for (float dy = -u_bordersize; dy < u_bordersize; dy++) {
             vec2 point = v_texCoords + vec2(dx,dy) * pixelToTextureCoords;
             float alpha = texture2D(u_texture, point).a;
    	 if (alpha < 0.5) isInteriorPoint = false;
    	 if (alpha > 0.5) isExteriorPoint = false;
          }
       }
       if (!isInteriorPoint && !isExteriorPoint && color.a<0.5)
          gl_FragColor = u_bordercolor;
       else gl_FragColor = v_color * color;
    }
    
    To use that shader requires multiple Java variables to be passed in:
    batch.setShader(sp);
    sp.setUniformf("u_imageSize", new Vector2(getWidth(), getHeight()));
    sp.setUniformf("u_borderColor", color.BLACK);
    sp.setUniformf("u_borderSize", 3.0);
    super.draw(batch, alpha); /* draw()'s alpha is not the GLSL alpha */
    batch.setShader(null);
    

    Blur Shader

    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform sampler2D u_texture;
    uniform vec2 u_imageSize;
    uniform int u_blurRadius;
    
    void main()
    {
       vec4 color = texture2D(u_texture, v_texCoords);
       vec2 pixelToTextureCoords = 1 / u_imageSize;
    
       for (float dx = -u_blurRadius; dx < u_blurRadius; dx++) {
          for (float dy = -u_blurRadius; dy < u_blurRadius; dy++) {
             vec2 point = v_texCoords + vec2(dx,dy) * pixelToTextureCoords;
    	 averageColor += texture2D(u_texture, point);
          }
       }
       averageColor /= pow(2.0 * u_blurRadius + 1.0, 2.0);
       gl_FragColor = v_color * averageColor;
    }
    

    Glow Shader

    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform sampler2D u_texture;
    uniform vec2 u_imageSize;
    uniform int u_glowRadius;
    
    void main()
    {
       vec4 color = texture2D(u_texture, v_texCoords);
       vec2 pixelToTextureCoords = 1 / u_imageSize;
       vec4 averageColor = vec4(0.0, 0.0, 0.0, 0.0);
       for (float dx = -u_glowRadius; dx < u_glowRadius; dx++) {
          for (float dy = -u_glowRadius; dy < u_glowRadius; dy++) {
             vec2 point = v_texCoords + vec2(dx,dy) * pixelToTextureCoords;
    	 averageColor += texture2D(u_texture, point);
          }
       }
       averageColor /= pow(2.0 * u_glowRadius + 1.0, 2.0);
       float amount = (sin(6.0 * u_time) + 1.0) * 0.5;
       vec4 glowFactor = vec4(2.0 * averageColor.rgb, averageColor.a);
    
       gl_FragColor = v_color * (color + amount * glowFactor);
    }
    

    Wave Distortion Shader

    This one features an interesting mixture of CPU and GPU work.
    varying vec4 v_color;
    varying vec2 v_texCoords;
    uniform float u_time;
    uniform vec2 u_imageSize;
    uniform vec2 u_amplitude;
    uniform vec2 u_wavelength;
    uniform vec2 u_velocity;
    
    uniform sampler2D u_texture;
    
    void main()
    {
       vec2 pixelCoords = v_texCoords * u_imageSize;
       vec2 offset = u_amplitude * sin(6.283/u_wavelength*
    				    (pixelCoords.yx - u_velocity * u_time));
       vec2 texCoords = v_texCoords + offset / u_imageSize;
       gl_FragColor = v_color * texture2D(u_texture, texCoords);
    }
    
    When a shader requires most of its data from Java variables that are passed in, one might say that the CPU is doing a fair part of the work, albeit not in parallel.
    batch.setShader(sp);
    sp.setUniformf("u_time", time);
    sp.setUniformf("u_imageSize", new Vector2(getWidth(), getHeight()));
    sp.setUniformf("u_amplitude", new Vector2(2, 3));
    sp.setUniformf("u_wavelength", new Vector2(7, 19));
    sp.setUniformf("u_velocity", new Vector2(10, 11));
    super.draw(batch, alpha);
    batch.setShader(null);
    

    lecture 38

    lecture 39

    Lectures 38-39 were replaced by student level 1 demos.

    lecture 40

    Intro to 3D Graphics and Games

    3D is a major subject for CS 428/528, but it is fair game for us to see what Stemkoski has to say in Ch 16. Consider this a bonus topic for CS 328. It is also inevitable that much of this material will be presented in that course, with a different textbook author's voice.

    Ch 16 Demos

    If possible we will run them.

    3D and Cameras

    Rendering Code vs. Data: Algorithms vs. Models

    It is a bit of a false dichotomy, but OpenGL lets you render graphics by either:

    3D Code vs. Data Illustration

    In the early days of my CVE collaborative virtual environment, students wrote classes representing different kinds of things in the virtual world, such as tables and chairs.

    Code vs. Models in libGDX

    In libGDX the Code vs. Data dichotomy is reflected in the classes ModelBuilder vs. ModelLoader. If you are coding your 3D scene, you are using a ModelBuilder with methods like createBox():
    ModelBuilder modelBuilder = new ModelBuilder();
    
    Material boxMaterial = new Material();
    boxMaterial.set(ColorAttribute.createDiffuse(Color.BLUE));
    int usageCode = Usage.Position + Usage.ColorPacked + Usage.Normal;
    
    Model boxModel = modelBuilder.createBox( 5, 5, 5, boxMaterial, usageCode);
    boxInstance = new ModelInstance(boxModel);
    
    To actually draw the mode:
    modelBatch.begin(camera);
    modelBatch.render(boxInstance, environment);
    modelBatch.end();
    

    Ch 16 Code

    We will look at the highlights.

    The BaseActor3D class

    class BaseActor3D {
       private ModelInstance modelData;
       // Could do all 3 of these with one mat4, but...
       private final Vector3 position;
       private final Quaternion rotation;
       private final Vector3 scale;
       // ... lots of easy one-liner methods:
       public void moveBy(Vector3 v) { position.add(v); }
    }
    
    The only methods that aren't one liners in BaseActor3D are those that tweak the model's color/texture, and it is almost the same for loop in each case.
    public void setColor(Color c)
    {
       for (Material m : modelData.materials)
          m.set( ColorAttribute.createDiffuse(c));
    }
    public void loadTexture(String fileName)
    {
       Texture tex = new Texture(Gdx.files.internal(fileName, true));
       tex.setFilter( TextureFilter.Linear, TextureFilter.Linear);
       for (Material m : modelData.materials)
          m.set( TextureAttribute.createDiffuse(tex));
    }
    

    lecture 41

    Stemkoski's Stage3D class

    public class Stage3D {
       private Environment environment;
       private PerspectiveCamera camera;
       private final ModelBatch modelBatch;
       private ArrayList<BaseActor3D> actorList;
    
       // ... big constructor sets up lighting and camera
       public Stage3D() {
          environment = new Environment();
          environment.set(new ColorAttribute(ColorAttribute.AmbientLight,
             0.7f, 0.7f, 0.7f, 1));
          DirectionalLight dLite = new DirectionalLight();
          Color lightColor = new Color(0.9f, 0.9f, 0.9f, 1);
          Vector3 lightVector = new Vector3(-1.0f, -0.75f, -0.25f);
          dLite.set(lightColor, lightVector);
          environment.add(dLite);
          camera = new PerspectiveCamera(67,
          	Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
          camera.position.set(10f,10f,10f);
          camera.lookAt(0,0,0);
          camera.near(0.01f);
          camera.far(1000f);
          camera.update();
          modelBatch = new ModelBatch();
          actorList = new ArrayList<BaseActor3D>()
       }
    
    
       // ... methods mainly iterate over actors on actorList
       public void draw() {
          modelBatch.begin(camera);
          for (BaseActor3D ba : actorList)
             ba.draw(modelBatch, environment);
          modelBatch.end();
       }
    }
    
    Reactions:

    "Interactive 3D Demo" Code Notes

    Starfish Collector 3D Code Highlights

    Actual skydome code looks anticlimactic. Hardest part was constructing the sphere-distorted 2D rectangular texture image, which is not covered in our book, but googling "how to construct a skydome texture" seems to turn up some promising links. Anyhow, the code:
      Sphere skydome = new Sphere(0,0,0,mainStage3D);
      skydome.loadTexture("assets/sky-sphere.png");
      skydome.setScale(500,500,-500);    // one might use even bigger numbers
    
    There are multiple levels of instantiation of factory classes that produce things that require instantiation...but to sum up:
    public class ObjModel extends BaseActor3D {
    ...
      public void loadObjModel(String fileName) {
        ObjLoader loader = new ObjLoader();
        Model objModel = loader.loadModel(Gdx.files.internal(fileName), true);
        setModelInstance(new ModelInstance(objModel));
      }
    }
    
    and for the actual Turtle class in 3D:
    public class Turtle extends ObjModel
    {
       public void Turtle(float, float y, float z, Stage3D s) {
          super(x,y,z,s);
          loadObjModel("assets/turtle.obj");
          setBasePolygon(); // sets bounding box for collision detection
       }
    }
    

    Major Sources of 3D Assets

    These are all worth checking out. Personally I am most familiar with TurboSquid, but have also used opengameart before.

    lecture 42

    These items are from Stemkoski Ch. 17.

    More Resources

    Game Jams

    Packaging Your Games for Distribution

    Games-Related Research

    Here are some of the types of research I want to work with students on, related to computer games or game-like software systems. Some of these are pursuable via directed studies while others are more like senior project or M.S. thesis or Ph.D. dissertation material.
    programming language support for games
    "language support" means: portable multi-platform higher-level facilities, includign data and control structures, operators and built-in functions. Much of what I've added to Unicon has ended up being I/O-oriented, such as easy graphics and networking. There is room for more I/O, such as portable multi-platform touch/gestures, and ports to more platforms. To identify what is needed, besides supporting new hardware or OSes: look at current games and identify their costs/pain points. Wow took $150M to develop initially. How can we reduce that cost and enable new garage startups in such a space?
    asset tools and libraries
    For the vast majority of commercial games, the art and modeling assets consume the vast majority of the budget. Example: a boss at Westwood studios (makers of Command and Conquer, Dune, etc.) once told me that for their typical titles, 3-5 programmers work with 30-50 artists. What can't be done wholly by code can be reduced in cost by improving tools and libraries.
    game AI, such as better NPC A/I
    NPC's in many major commercial titles (e.g. Wow) still have pretty trivial AI. If we are in the midst of an AI revolution, and have CPU to burn, we should be able to do way better. Some games do better than others already, of course. STALKER Shadow of Chernobyl is said to have NPC's who live in packs and do stuff independent of player actions. GTA apparently has a very clever police force. I am interested in NPC's that remember past interactions, have their own agenda that they will pursue with or without you, etc. A couple current M.S. students are working on smarter NPC's with me at present.
    rebalancing persistent virtual worlds content
    One thing I hate in MMOs is that player successes have no lasting effect. The world needs an MMO where if you topple the enemy boss, the world is changed forever by that action. Instead of static state, games need to move to state that rebalances as a result of players.
    user-generated virtual worlds content
    The main thing causing some folks to quit some games is that they run out of new content. There have been major games that featured user-created worlds (Minecraft, Second Life), but few that provided user-created story lines and quests. City of Heroes started to do this towards the end of its life, maybe there are others. This is a sort of crowd-sourcing the content creation, and it needs to be quality-controlled, perhaps by end-user rating system, perhaps by super-user vetting.
    procedurally-generated city structures
    I have started working with a city metaphor for software visualization. I am interested in generating a city or collection of cities that are reflections of software's static structures.
    execution-driven city population and behavior
    I did my Ph.D. on high performance execution monitoring; I want to use program execution behavior to dynamically spawn NPC's and guide their subsequent behavior within the generated cities.

    More Intellectual Property

    From the slide deck

    Content Regulation

    slide deck