to the Core
Adding the fun of physics to PulpCore games!
General Demo

Created with PulpCore
 // GeneralDemo.java
package simpull2core.demo.general;

import pulpcore.Input;
import pulpcore.animation.Timeline;
import pulpcore.image.Colors;
import pulpcore.image.CoreFont;
import pulpcore.image.CoreImage;
import pulpcore.sprite.FilledSprite;
import pulpcore.sprite.ImageSprite;
import pulpcore.sprite.Label;
import simpull.Circle;
import simpull.Composite;
import simpull.CustomBodyFinisher;
import simpull.Particle;
import simpull.Rectangle;
import simpull.SimpleSpring;
import simpull.VectorForce;
import simpull2core.CustomBodyViewFinisher;
import simpull2core.SimpullFactory;
import simpull2core.SimpullScene2D;
import simpull2core.SimpullToTheCoreComposite;

public class GeneralDemo extends SimpullScene2D {
	
	private Composite star, tumbler;
	private Particle pendulum;

	public GeneralDemo() {
		super(new VectorForce(false, 0f, 3f));
	}
	
	@Override
	@SuppressWarnings("unchecked")
	protected void loadInternal() {
		CoreImage rock1 = CoreImage.load("img/rock1.png");
		CoreImage rock2 = CoreImage.load("img/rock2.png");
		CoreImage branch1 = CoreImage.load("img/branch1.png");
		CoreImage branch2 = CoreImage.load("img/branch2.png");
		
		// Add just a plain ole PulpCore image to the scene for the background.
		add(new ImageSprite(CoreImage.load("img/bg.jpg"), 0, 0));
		
		{ // set up the branch(es) in the upper right corner
			ImageSprite thickBranchImg = new ImageSprite(branch1, 785, 90);
			thickBranchImg.angle.set(0.4);
			add(SimpullFactory.createRectangle(thickBranchImg, true, 1, 0, 1), thickBranchImg, true);

			ImageSprite thickBranchImg2 = new ImageSprite(branch1, 746, 79);
			thickBranchImg2.angle.set(0.2);
			add(SimpullFactory.createRectangle(thickBranchImg2, true, 1, 0, 1), thickBranchImg2, true);
	
			ImageSprite thinBranchImg = new ImageSprite(branch2, 710, 72);
			add(SimpullFactory.createRectangle(thinBranchImg, true, 1, 0, 1), thinBranchImg, true);
		}
		
		{ // star 
			CoreImage star4Img = CoreImage.load("img/star4.png");
			star = new Composite(false, 8);
			// The top-left point of the star is (710, 10), so I got the points
			// on the start from the image creation software and added the reference 
			// location to get a good physical representation...cool trick!
			star.add(new Circle(14 + 710, 7 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(29 + 710, 0 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(20 + 710, 14 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(29 + 710, 29 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(14 + 710, 22 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(0 + 710, 29 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(7 + 710, 14 + 10, 1f, false, 1f, 0.3f, 1f));
			star.add(new Circle(0 + 710, 0 + 10, 1f, false, 1f, 0.3f, 1f));
			star.setCompositeCompleted(new CustomBodyFinisher(3, 1));
			ImageSprite wheelSpriteA = new ImageSprite(star4Img, 0, 0);
			add(star, wheelSpriteA, true);
		}
		
		Label bounceTxt = new Label(CoreFont.getSystemFont().tint(Colors.WHITE), "Arrow keys!", 750, 15);
		bounceTxt.setAnchor(Label.CENTER);
		add(bounceTxt);
		Timeline timeline = new Timeline();
		timeline.at(0).animate(bounceTxt.angle, 0, Math.PI / 5, 300);
		timeline.at(300).animate(bounceTxt.angle, Math.PI / 5, -Math.PI / 5, 600);
		timeline.at(900).animate(bounceTxt.angle, -Math.PI / 5, 0, 300);
		timeline.loopForever();
		addTimeline(timeline);
		
		{ // The tumbler
			SimpullToTheCoreComposite stcTumbler = new SimpullToTheCoreComposite(true, 20);
			CoreImage connectorImg = CoreImage.load("img/connector.png");
			CoreImage grateImg = CoreImage.load("img/grate.jpg");
			
			ImageSprite connector1 = new ImageSprite(connectorImg, 50, 10);
			Circle connector1circle = SimpullFactory.createCircle(connector1, false, 1, 0.3f, 0);
			stcTumbler.add(connector1circle, connector1);
			
			ImageSprite connector2 = new ImageSprite(connectorImg, 150, 10);
			Circle connector2circle = SimpullFactory.createCircle(connector2, false, 1, 0.3f, 0);
			stcTumbler.add(connector2circle, connector2);
			
			ImageSprite connector3 = new ImageSprite(connectorImg, 100, 60);
			Circle connector3circle = SimpullFactory.createCircle(connector3, false, 1, 0.3f, 0);
			stcTumbler.add(connector3circle, connector3);
			
			// Finish the body by connecting the particles we just added with some constraints that have grateImg
			// as a view (scaled to the right size to fit between each particle).
			stcTumbler.setCompositeCompleted(new CustomBodyViewFinisher(stcTumbler, grateImg, true, 0.9f));
			add(stcTumbler, true);
			tumbler = stcTumbler.getComposite();
		}
		
		{ // TODO water inside the tumbler
			for (int i = 0; i < 0; ++i) {
				FilledSprite waterDrop = new FilledSprite(70 + i, 25, 5, 5, Colors.BLUE);
				add(SimpullFactory.createCircle(waterDrop, false, 0.01f, 0.1f, 0), waterDrop, true);
			}
		}
		
		// Until the water is ready, use a wheel inside to tumble
		CoreImage wheelImg = CoreImage.load("img/wheel.png");
		ImageSprite tumbleWheel = new ImageSprite(wheelImg.halfSize(), 90, 35);
		add(SimpullFactory.createWheel(tumbleWheel, false, 0.5f, 0.3f, 0, 1), tumbleWheel, true);
		
		// add a mountain (cosine wave), with walls at the edge of the screen up to the height of the wave
		final int iterations = 50;
		final float xMax = 800f / ((float)Math.PI * 2f);
		float lastDangleX = 0f;
		CoreImage squareWheelImg = CoreImage.load("img/squareWheel.jpg");
		for (int i = 0; i < iterations; ++i) {
			CoreImage img = (i % 2 == 0) ? rock1 : rock2;
			float x = (float)Math.PI * 2f * ((float)i / (float)iterations);
			float worldX = x * xMax;
			float y = (float)Math.cos(x) * 100 + 330;
			ImageSprite rock = new ImageSprite(img, worldX, y);
			rock.angle.set(Math.random() * Math.PI * 2);
			Rectangle rockRect = SimpullFactory.createRectangle(rock, true, 1, 0.3f, 0);
			add(rockRect, rock, true);
			// Every so often, add a side wall rock piece on either side
			if (i % 4 == 0) {
				ImageSprite right = new ImageSprite(img, 795, y);
				ImageSprite left = new ImageSprite(img, 5, y);
				right.angle.set(Math.random() * Math.PI * 2);
				left.angle.set(Math.random() * Math.PI * 2);
				add(SimpullFactory.createRectangle(left, true, 1, 0.3f, 0), left, true);
				add(SimpullFactory.createRectangle(right, true, 1, 0.3f, 0), right, true);
			}
			// If the spacing is right, add a dangling participle!!!
			if (worldX > 130 && worldX < 680) {
				if ((worldX - lastDangleX) > 31) {
					lastDangleX = worldX;
					float magic = worldX > 400 ? 800 - worldX : worldX;
					ImageSprite dangler = null;
					Rectangle danglerRect = null;
					if (pendulum == null) {
						dangler = new ImageSprite(squareWheelImg.tint(Colors.YELLOW), worldX, y + 25 + (magic / 4));
						danglerRect = SimpullFactory.createRectangle(dangler, false, 2, 0.3f, 0);
						pendulum = danglerRect;
					} else {
						dangler = new ImageSprite(squareWheelImg, worldX, y + 25 + (magic / 4));
						danglerRect = SimpullFactory.createRectangle(dangler, false, 2, 0.3f, 0);
					}
					add(danglerRect, dangler, true);
					SimpleSpring spring = new SimpleSpring(rockRect, danglerRect, 0.5f, false, 2, 1, false);
					add(spring, SimpullFactory.createDefaultView(spring, Colors.rgb(153, 127, 102)), true);
				}
			}
		}
		
		Label pendulumTxt = new Label("A must have in a physics demo!", 400, 425);
		pendulumTxt.setAnchor(Label.CENTER);
		add(pendulumTxt);
		Timeline timeline2 = new Timeline();
		timeline2.at(0).animate(pendulumTxt.x, 400, 450, 500);
		timeline2.at(0).animate(pendulumTxt.y, 425, 435, 500);
		timeline2.at(500).animate(pendulumTxt.x, 450, 400, 500);
		timeline2.at(500).animate(pendulumTxt.y, 435, 445, 500);
		timeline2.at(1000).animate(pendulumTxt.x, 400, 350, 500);
		timeline2.at(1000).animate(pendulumTxt.y, 445, 435, 500);
		timeline2.at(1500).animate(pendulumTxt.x, 350, 400, 500);
		timeline2.at(1500).animate(pendulumTxt.y, 435, 425, 500);
		timeline2.loopForever();
		addTimeline(timeline2);
		
//		FilledSprite floor = new FilledSprite(400, 240, 800, 20, Colors.WHITE);
//		add(SimpullFactory.createRectangle(floor, true, 1, 0.3f, 0), floor, true);
		
		{ // left side of tires
			float x = 340;
			ImageSprite leftWheel1 = new ImageSprite(wheelImg, x, 200);
			add(SimpullFactory.createWheel(leftWheel1, false, 2, 0.3f, 0, 1), leftWheel1, true);
			ImageSprite leftWheel2 = new ImageSprite(wheelImg, x, 160);
			add(SimpullFactory.createWheel(leftWheel2, false, 2, 0.3f, 0, 1), leftWheel2, true);
			ImageSprite leftWheel3 = new ImageSprite(wheelImg, x, 120);
			add(SimpullFactory.createWheel(leftWheel3, false, 2, 0.3f, 0, 1), leftWheel3, true);
			ImageSprite leftWheel4 = new ImageSprite(wheelImg, x, 80);
			add(SimpullFactory.createWheel(leftWheel4, false, 2, 0.3f, 0, 1), leftWheel4, true);
			ImageSprite leftWheel5 = new ImageSprite(wheelImg, x, 40);
			add(SimpullFactory.createWheel(leftWheel5, false, 2, 0.3f, 0, 1), leftWheel5, true);
			ImageSprite leftWheel6 = new ImageSprite(wheelImg, x, 0);
			add(SimpullFactory.createWheel(leftWheel6, false, 2, 0.3f, 0, 1), leftWheel6, true);
		}
		{ // right side of tires
			float x = 460;
			ImageSprite leftWheel1 = new ImageSprite(wheelImg, x, 200);
			add(SimpullFactory.createWheel(leftWheel1, false, 2, 0.3f, 0, 1), leftWheel1, true);
			ImageSprite leftWheel2 = new ImageSprite(wheelImg, x, 160);
			add(SimpullFactory.createWheel(leftWheel2, false, 2, 0.3f, 0, 1), leftWheel2, true);
			ImageSprite leftWheel3 = new ImageSprite(wheelImg, x, 120);
			add(SimpullFactory.createWheel(leftWheel3, false, 2, 0.3f, 0, 1), leftWheel3, true);
			ImageSprite leftWheel4 = new ImageSprite(wheelImg, x, 80);
			add(SimpullFactory.createWheel(leftWheel4, false, 2, 0.3f, 0, 1), leftWheel4, true);
			ImageSprite leftWheel5 = new ImageSprite(wheelImg, x, 40);
			add(SimpullFactory.createWheel(leftWheel5, false, 2, 0.3f, 0, 1), leftWheel5, true);
			ImageSprite leftWheel6 = new ImageSprite(wheelImg, x, 0);
			add(SimpullFactory.createWheel(leftWheel6, false, 2, 0.3f, 0, 1), leftWheel6, true);
		}
	}
	
	@Override
	protected void updatePrePhysics() {
		float vel = 0.5f;
		float lessVel = vel / 5f;
		if (Input.isDown(Input.KEY_LEFT)) {
			star.setAngularVelocity(-vel);
			pendulum.addForce(new VectorForce(true, -40, 0));
			tumbler.setAngularVelocity(-lessVel);
		} else if (Input.isDown(Input.KEY_RIGHT)) {
			star.setAngularVelocity(vel);
			pendulum.addForce(new VectorForce(true, 40, 0));
			tumbler.setAngularVelocity(lessVel);
		} else if (Input.isReleased(Input.KEY_LEFT) || Input.isReleased(Input.KEY_RIGHT)) {
			star.setAngularVelocity(0);
			tumbler.setAngularVelocity(0);
		}
	}

}